import { LatLngExpression } from 'leaflet';
import React from 'react';
import { Marker, Polyline, Popup } from 'react-leaflet';
import {
	erSann,
	garanterListe,
	GENERELL_PLANTYPE_KONTRAKT,
	GENERELL_PLANTYPE_OMRAADE,
	GyldighetsRegistrerer,
	ledetekst,
	markorikon,
	OppsummeringBlokk,
	OppsummeringPunkt,
	OppsummeringTabell,
	OppsummeringUnderpunkt,
	PLANTYPE_GENERELL,
	PLANTYPE_SPESIELL,
	useOppsummering,
	varslingsikon,
	VerdiEllerInfoMangler,
} from '..';
import { validerSted } from '../validering/StedValidering';
import {
	getFartsgrenser,
	getHoyesteTrafikkmengde,
	getNyesteFartsgrense,
	getNyesteTrafikkmengde,
	vegsystemreferanseTilKortformMedTrafikantgruppe,
} from '../vegsystem/utils';
import { Kart } from './Kart';
import { TilbakemeldingForSteg } from './tilbakemelding/TilbakemeldingForSteg';
import { erUlikeObjekter, finnesElementIListe } from './utils';
import {
	Arbeidsruter,
	Fylke,
	Kontraktsomraade,
	OmraadeGenerellPlan,
	Soknad,
	Vegarbeidsposisjoner,
} from '../domene/Soknad';
import { SlettetInformasjonsboks } from './SlettetInformasjonsboks';
import _ from 'lodash';

export function StedOppsummering() {
	const {
		kunLesbar,
		vegarbeid,
		plantype,
		id: soknadId,
		gyldighet,
		soknad,
		forrigeSoknad,
	} = useOppsummering() as any;
	const arbeidssted = vegarbeid?.arbeidssted;
	const vegarbeidssted = vegarbeid?.vegarbeidssted;

	const valideringsfeil = !kunLesbar && validerSted(soknad);
	const redigeringsLenke = !kunLesbar && `#/${soknadId}/vegarbeidomrade`;

	const ingenPlantype = !plantype;

	return (
		<>
			<TilbakemeldingForSteg steg="vegarbeidomrade" />
			<OppsummeringBlokk
				tittel={ledetekst.getTekst(
					'arbeidsvarsling.soknad.Soknadskomponent.kulepunkter.Vegarbeidomrade'
				)}
				redigeringsLenke={redigeringsLenke}
				valideringsfeil={valideringsfeil}
				ikon={'ikon-sted'}
				ingenBakgrunn={ingenPlantype}
			>
				{!ingenPlantype && (
					<>
						{plantype === PLANTYPE_GENERELL && (
							<GenerellPlanOppsummering
								omraadeGenerellPlan={
									vegarbeidssted.omraadeGenerellPlan || {}
								}
								forrigeSoknad={forrigeSoknad}
							/>
						)}
						{plantype === PLANTYPE_SPESIELL && (
							<SpesiellPlanOppsummering
								vegarbeidsposisjoner={garanterListe(
									vegarbeidssted.vegarbeidsposisjoner
								)}
								arbeidsruter={arbeidssted.arbeidsruter || []}
								forrigeSoknad={forrigeSoknad}
							/>
						)}
					</>
				)}

				<GyldighetsRegistrerer
					gyldighet={gyldighet.obligatorisk()}
					erGyldig={!valideringsfeil}
				/>
			</OppsummeringBlokk>
		</>
	);
}

export function getGenerellPlantype(omraadeGenerellPlan?: OmraadeGenerellPlan) {
	if (garanterListe(omraadeGenerellPlan?.fylker).length > 0) {
		return GENERELL_PLANTYPE_OMRAADE;
	} else if (omraadeGenerellPlan?.kontraktsomraade) {
		return GENERELL_PLANTYPE_KONTRAKT;
	}
}

function GenerellPlanOppsummering(props) {
	const { omraadeGenerellPlan, forrigeSoknad } = props;
	const typeGenerellPlan = getGenerellPlantype(omraadeGenerellPlan);

	return (
		<OppsummeringPunkt
			tittel={ledetekst.getTekst(
				'arbeidsvarsling.soknad.Oppsummering.Vegarbeidssted.omrade'
			)}
		>
			{typeGenerellPlan === GENERELL_PLANTYPE_KONTRAKT ? (
				<KontraktOppsummering
					kontrakt={omraadeGenerellPlan.kontraktsomraade || {}}
					forrigeSoknad={forrigeSoknad}
				/>
			) : (
				<FylkeKommuneOppsummering
					fylker={omraadeGenerellPlan.fylker || []}
					forrigeSoknad={forrigeSoknad}
					omraadeGenerellPlan={omraadeGenerellPlan}
				/>
			)}
		</OppsummeringPunkt>
	);
}

function fartsgrenserTilTekst(fartsgrenser) {
	// fjerner duplikater fra fartsgrenser
	return [...new Set(fartsgrenser)].join(', ');
}

function trafikkmengdeTilTekst(trafikkmengde) {
	return ledetekst
		.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.trafikkmengde',
			trafikkmengde.arsdognstrafikk,
			trafikkmengde.andelLangeKjoretoy
				? ledetekst.getTekst(
						'arbeidsvarsling.soknad.Vegrutevisning.trafikkmengde.andellange',
						trafikkmengde.andelLangeKjoretoy
				  ) + ', '
				: '',
			trafikkmengde.gjelderAr
		)
		.replace(/\s/g, '\u00A0');
}

function KontraktOppsummering({
	kontrakt,
	forrigeSoknad,
}: {
	kontrakt: Kontraktsomraade;
	forrigeSoknad: Soknad;
}) {
	if (!kontrakt) return null;

	const markerEndretKontrakt =
		!!forrigeSoknad &&
		erUlikeObjekter(
			kontrakt,
			forrigeSoknad.vegarbeid?.vegarbeidssted?.omraadeGenerellPlan
				?.kontraktsomraade
		);

	return (
		<OppsummeringUnderpunkt
			overskrift={ledetekst.getTekst(
				'arbeidsvarsling.soknad.Vegarbeidomrade.generell.kontraktsomrade'
			)}
			className={
				markerEndretKontrakt
					? 'saksbehandling-redigert-informasjon'
					: ''
			}
		>
			<p className="inline" data-hj-suppress>
				{kontrakt.navn}
			</p>
			(
			<a
				href={
					"https://www.vegvesen.no/vegkart/vegkart/#kartlag:geodata/hva:(~(farge:'0_1,id:532))/hvor:(kontraktsomrade:(~'" +
					kontrakt.navn.replace(' ', '*20') +
					'))'
				}
				rel="noopener noreferer"
				target="_blank"
			>
				Vegkart
			</a>
			)
		</OppsummeringUnderpunkt>
	);
}

function FylkeKommuneOppsummering({
	fylker,
	forrigeSoknad,
	omraadeGenerellPlan,
}: {
	fylker: Fylke[];
	forrigeSoknad?: Soknad;
	omraadeGenerellPlan?: OmraadeGenerellPlan;
}) {
	if (!fylker) return null;

	const overskrifter = [
		'arbeidsvarsling.soknad.Vegarbeidomrade.generell.omraade.fylker',
		'arbeidsvarsling.soknad.Vegarbeidomrade.generell.omraade.kommuner',
	].map(ledetekst.getTekst);

	const harSlettetInformasjon =
		!!forrigeSoknad &&
		forrigeSoknad.vegarbeid?.vegarbeidssted?.omraadeGenerellPlan?.fylker
			?.length > fylker.length;

	const data =
		fylker?.length > 0
			? fylker.map((fylke) => {
					return {
						kolonner: [
							fylke.fylkesnavn,
							fylke.kommuner
								.map((kommune) => kommune.kommunenavn)
								.join(', '),
						],
						markerEndring:
							!!forrigeSoknad &&
							erFylkeEndret(fylke, forrigeSoknad),
					};
			  })
			: [
					{
						kolonner: [null, null],
						markerEndring: false,
					},
			  ];
	const markerEndretVegtyper =
		!!forrigeSoknad &&
		erUlikeObjekter(
			omraadeGenerellPlan?.vegtyper,
			forrigeSoknad?.vegarbeid?.vegarbeidssted?.omraadeGenerellPlan
				?.vegtyper
		);

	return (
		<>
			<OppsummeringUnderpunkt
				className={
					markerEndretVegtyper
						? 'saksbehandling-redigert-informasjon'
						: ''
				}
				overskrift={ledetekst.getTekst(
					'arbeidsvarsling.soknad.Oppsummering.Vegarbeidssted.veger'
				)}
			>
				<VerdiEllerInfoMangler>
					{garanterListe(omraadeGenerellPlan?.vegtyper)
						.filter(erSann)
						.map((vegtype) =>
							ledetekst.getTekst(
								`arbeidsvarsling.soknad.Vegarbeidomrade.generell.vegtype.${vegtype}`
							)
						)
						.join(', ')}
				</VerdiEllerInfoMangler>
			</OppsummeringUnderpunkt>

			<OppsummeringUnderpunkt>
				<OppsummeringTabell
					data={data}
					overskrifter={overskrifter}
					kolonner={4}
					skalMaskeres={true}
				/>
				<SlettetInformasjonsboks
					vis={harSlettetInformasjon}
					tekst={'Fylke(r) har blitt slettet.'}
				/>
			</OppsummeringUnderpunkt>
		</>
	);
}

function SpesiellPlanOppsummering(props) {
	const { arbeidsruter, vegarbeidsposisjoner, forrigeSoknad } = props;

	return (
		<>
			<SpesiellPlanOppsummeringArbeidsruter
				arbeidsruter={arbeidsruter}
				forrigeSoknad={forrigeSoknad}
			/>

			<SpesiellPlanOppsummeringVegarbeidsposisjoner
				vegarbeidsposisjoner={vegarbeidsposisjoner}
				forrigeSoknad={forrigeSoknad}
			/>

			<StedfestingsKart
				arbeidsruter={arbeidsruter}
				vegarbeidsposisjoner={vegarbeidsposisjoner}
			/>
		</>
	);
}

function seViaVegbilder(punkter: LatLngExpression): JSX.Element {
	return (
		<Popup>
			<a
				target="_blank"
				href={`https://vegbilder.atlas.vegvesen.no/?lat=${punkter[0]}&lng=${punkter[1]}&zoom=15&view=map&year=latest`}
			>
				{ledetekst.getTekst(
					'arbeidsvarsling.frontendkomponenter.oppsummering.kart.vegbildeLenke'
				)}
			</a>
		</Popup>
	);
}

function StedfestingsKart({ arbeidsruter, vegarbeidsposisjoner }) {
	const ruter =
		arbeidsruter
			?.flatMap((a) => a.vegstrekninger)
			?.filter((strekning) => !!strekning)
			?.map((strekning) =>
				strekning.geometri?.map(({ x, y }) => [y, x])
			) ?? [];
	const posisjoner =
		arbeidsruter
			?.flatMap((a) => a.vegposisjoner)
			?.map(({ koordinat }) => [koordinat.y, koordinat.x]) ?? [];
	const varslingspunkter: [LatLngExpression, LatLngExpression] =
		vegarbeidsposisjoner
			?.map((a) => a.koordinat)
			?.map(({ x, y }) => [y, x]) ?? [];
	const { id: soknadId } = useOppsummering();
	return (
		<OppsummeringPunkt>
			<div data-hj-suppress>
				<Kart key={soknadId}>
					{ruter.map((rute, i) => (
						<Polyline key={`rute-${i}`} positions={rute} />
					))}
					{posisjoner.map((posisjon, i) => (
						<Marker
							key={`posisjon-${i}`}
							position={posisjon}
							icon={markorikon()}
						>
							{seViaVegbilder(posisjon)}
						</Marker>
					))}
					{varslingspunkter.map((punkt, i) => (
						<Marker
							key={`varslingspunkt-${i}`}
							position={punkt}
							icon={varslingsikon()}
						>
							{seViaVegbilder(punkt)}
						</Marker>
					))}
				</Kart>
			</div>
			<p>
				{ledetekst.getTekst(
					'arbeidsvarsling.frontendkomponenter.oppsummering.kart.tips.veglenker'
				)}{' '}
				<a href="https://vegbilder.atlas.vegvesen.no/?year=latest&lat=65&lng=15&zoom=4&view=map">
					{ledetekst.getTekst(
						'arbeidsvarsling.frontendkomponenter.oppsummering.kart.tips.vegbilder'
					)}
				</a>
			</p>
		</OppsummeringPunkt>
	);
}

function SpesiellPlanOppsummeringVegarbeidsposisjoner(props) {
	const { vegarbeidsposisjoner, forrigeSoknad } = props;

	const overskrifter = [
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.varslingspunkt',
			''
		),
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.vegreferanse',
			''
		),
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.fartsgrense'
		),
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.adt.nyeste'
		),
	];

	let data = vegarbeidsposisjoner.filter(erSann).map((vegposisjon, i) => {
		const fartsgrense = getNyesteFartsgrense(vegposisjon);
		const trafikkmengde = getNyesteTrafikkmengde(vegposisjon);
		const kolonner = [
			ledetekst.getTekst(
				'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.varslingspunkt',
				i + 1
			),
			String(
				vegsystemreferanseTilKortformMedTrafikantgruppe(
					vegposisjon.vegsystemreferanse
				)
			),
			fartsgrense ? fartsgrenserTilTekst([fartsgrense.fartsgrense]) : '-',
			trafikkmengde ? trafikkmengdeTilTekst(trafikkmengde) : '-',
		];
		return {
			kolonner: kolonner,
			markerEndring:
				!!forrigeSoknad &&
				erVegarbeidposisjonEndret(
					kolonner,
					forrigeSoknad?.vegarbeid?.vegarbeidssted
						?.vegarbeidsposisjoner
				),
		};
	});

	const harSlettetVegarbeidsposisjoner =
		forrigeSoknad &&
		forrigeSoknad?.vegarbeid?.vegarbeidssted?.vegarbeidsposisjoner?.filter(
			erSann
		)?.length > vegarbeidsposisjoner.filter(erSann)?.length;

	return (
		<OppsummeringPunkt
			tittel={ledetekst.getTekst(
				'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.vegarbeidsomrade'
			)}
		>
			<OppsummeringTabell
				overskrifter={overskrifter}
				kolonner={4}
				data={data}
				skalMaskeres={true}
			/>
			<SlettetInformasjonsboks
				vis={harSlettetVegarbeidsposisjoner}
				tekst={'Vegarbeidposisjon(er) har blitt slettet.'}
			/>
		</OppsummeringPunkt>
	);
}

function erVegarbeidposisjonEndret(
	kolonner: string[],
	vegarbeidposisjonerSammenligning: Vegarbeidsposisjoner[]
): boolean {
	if (!vegarbeidposisjonerSammenligning) return false;

	return !vegarbeidposisjonerSammenligning.some((forrigeVegposisjon, i) => {
		const fartsgrense = getNyesteFartsgrense(forrigeVegposisjon);
		const trafikkmengde = getNyesteTrafikkmengde(forrigeVegposisjon);
		const kolonnerForrigeSoknad = [
			ledetekst.getTekst(
				'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.varslingspunkt',
				i + 1
			),
			String(
				vegsystemreferanseTilKortformMedTrafikantgruppe(
					forrigeVegposisjon.vegsystemreferanse
				)
			),
			fartsgrense ? fartsgrenserTilTekst([fartsgrense.fartsgrense]) : '-',
			trafikkmengde ? trafikkmengdeTilTekst(trafikkmengde) : '-',
		];

		//Ikke sammenligne navn på sted, men alt annet
		return kolonnerForrigeSoknad.every((value, indeks) =>
			indeks === 0 ? true : value === kolonner[indeks]
		);
	});
}

function SpesiellPlanOppsummeringArbeidsruter(props) {
	const { arbeidsruter, forrigeSoknad } = props;

	const overskrifter = [
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.kart.Arbeid.arbeidssted',
			''
		),
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.arbeidsomrade.arbeidspunkt',
			''
		),
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.vegreferanse',
			''
		),
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.fartsgrenser'
		),
		ledetekst.getTekst(
			'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.adt'
		),
	];

	let data = arbeidsruter.filter(erSann).flatMap((rute, i) => {
		const vegposisjoner = rute.vegposisjoner;
		const fartsgrenser = getFartsgrenser(rute.vegstrekninger);
		const trafikkmengde = getHoyesteTrafikkmengde(rute.vegstrekninger);
		return vegposisjoner.map((vegposisjon, j) => {
			const punkt = getPunkt(j, vegposisjoner.length);

			const kolonner = [
				getStedTekst(j, i),
				getPunktTekst(punkt, vegposisjoner.length, j),
				getVegreferanseTekst(vegposisjon),
				getFartsgrensetekst(j, fartsgrenser),
				getTrafikkmengdeTekst(j, trafikkmengde),
			];

			return {
				kolonner: kolonner,
				markerEndring:
					forrigeSoknad &&
					erArbeidsruteEndret(
						kolonner,
						arbeidsruter,
						forrigeSoknad?.vegarbeid?.arbeidssted?.arbeidsruter.filter(
							erSann
						)
					),
			};
		});
	});

	if (data.length === 0) {
		data = [{ kolonner: ['', '', '', '', ''], markerEndring: false }];
	}

	const harSlettetArbeidsruter =
		forrigeSoknad &&
		forrigeSoknad?.vegarbeid?.arbeidssted?.arbeidsruter?.filter(erSann)
			?.length > arbeidsruter.filter(erSann)?.length;

	return (
		<OppsummeringPunkt
			tittel={ledetekst.getTekst(
				'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.arbeidsomrade'
			)}
		>
			<OppsummeringTabell
				overskrifter={overskrifter}
				kolonner={5}
				data={data}
				skalMaskeres={true}
			/>
			<SlettetInformasjonsboks
				vis={harSlettetArbeidsruter}
				tekst={'Arbeidsområde(r) har blitt slettet.'}
			/>
		</OppsummeringPunkt>
	);
}

function erFylkeEndret(fylke: Fylke, forrigeSoknad: Soknad): boolean {
	const fylkerForrigeSoknad =
		forrigeSoknad.vegarbeid?.vegarbeidssted?.omraadeGenerellPlan?.fylker;
	return !finnesElementIListe(fylke, fylkerForrigeSoknad);
}

function erArbeidsruteEndret(
	kolonner: string[],
	arbeidsruter: Arbeidsruter[],
	arbeidsruterTilSammenligning?: Arbeidsruter[]
): boolean {
	if (!arbeidsruterTilSammenligning) return false;

	return !arbeidsruterTilSammenligning.some((rute, i) => {
		const vegposisjonerForrigeSoknad = rute.vegposisjoner;
		const fartsgrenser = getFartsgrenser(rute.vegstrekninger);
		const trafikkmengdeRute = getHoyesteTrafikkmengde(rute.vegstrekninger);

		return vegposisjonerForrigeSoknad.some((vegposisjon, j) => {
			const vegpunkt = getPunkt(j, vegposisjonerForrigeSoknad.length);

			const kolonnerTilSammenligning = [
				getStedTekst(j, i),
				getPunktTekst(vegpunkt, vegposisjonerForrigeSoknad.length, j),
				getVegreferanseTekst(vegposisjon),
				getFartsgrensetekst(j, fartsgrenser),
				getTrafikkmengdeTekst(j, trafikkmengdeRute),
			];
			//Ikke sammenligne navn på sted, men alt annet
			const kolonneFinnes = _.isEqual(
				kolonnerTilSammenligning.slice(1),
				kolonner.slice(1)
			);

			//Selv om kolonne finnes, kan det hende at den totale arbeidsruten er endret
			const finnesAllePunkterPaArbeidsruten = _.some(
				arbeidsruter,
				(item) => {
					return _.isEqual(
						_.pick(item, ['punkter']),
						_.pick(rute, ['punkter'])
					);
				}
			);

			return kolonneFinnes && finnesAllePunkterPaArbeidsruten;
		});
	});
}

function getPunkt(j: number, length: number): string {
	return j === 0 ? 'fra' : j === length - 1 ? 'til' : 'via';
}

function getStedTekst(j: number, i: number): string {
	return j === 0
		? ledetekst.getTekst(
				'arbeidsvarsling.soknad.kart.Arbeid.arbeidssted',
				i + 1
		  )
		: ' ';
}

function getPunktTekst(punkt: string, length: number, j: number): string {
	return ledetekst.getTekst(
		'arbeidsvarsling.soknad.Oppsummering.Vegarbeidomrade.arbeidsomrade.arbeidspunkt.' +
			punkt,
		length > 3 ? j : ''
	);
}

function getVegreferanseTekst(vegposisjon: any): string {
	return vegposisjon
		? vegsystemreferanseTilKortformMedTrafikantgruppe(
				vegposisjon.vegsystemreferanse
		  )
		: '';
}

function getFartsgrensetekst(j: number, fartsgrenser: any[]): string {
	return j === 0
		? fartsgrenser.length > 0
			? fartsgrenserTilTekst(fartsgrenser)
			: '-'
		: ' ';
}

function getTrafikkmengdeTekst(j: number, trafikkmengde: any): string {
	return j === 0
		? trafikkmengde
			? trafikkmengdeTilTekst(trafikkmengde)
			: '-'
		: ' ';
}
