<script lang="ts">
	import { onMount } from 'svelte';
	import { page } from '$app/state';
	import GameMap from '$lib/components/GameMap.svelte';
	import CarteRegions, { type MarqueurCarte } from '$lib/components/CarteRegions.svelte';
	import PhotoPanel from '$lib/components/PhotoPanel.svelte';
	import StreetPanel from '$lib/components/StreetPanel.svelte';
	import ResultPanel from '$lib/components/ResultPanel.svelte';
	import TimerRing from '$lib/components/TimerRing.svelte';
	import { t } from '$lib/i18n/store.svelte';
	import { defi } from '$lib/stores/defi.svelte';
	import type { Coordonnees, GuessResult, RoundPlace } from '$lib/types';

	let { data } = $props();
	const mode = $derived(data.mode);

	const regionParam = $derived(page.url.searchParams.get('region'));
	const timerActif = $derived(page.url.searchParams.get('timer') === '1');

	let place = $state<RoundPlace | null>(null);
	let guess = $state<Coordonnees | null>(null);
	let result = $state<GuessResult | null>(null);
	let indicesMontres = $state<string[]>([]);
	let chargement = $state(true);
	let erreur = $state(false);
	let enCours = $state(false); // requête guess en vol

	let timerRef: ReturnType<typeof TimerRing> | undefined = $state();
	let joues = $state<string[]>([]); // ids déjà joués (évite les répétitions)
	let bilan = $state(false); // écran final du défi

	const estDefi = $derived(mode === 'defi');
	const mancheCourante = $derived(defi.manches.length + 1);
	const defiTermine = $derived(estDefi && defi.termine);
	// Marqueurs du récap SVG : position réelle (vert) + guess du joueur (corail),
	// numérotés par manche ; une manche passée (guess null) n'a que le point réel.
	const marqueursRecap = $derived(
		defi.manches.flatMap((m, i): MarqueurCarte[] => {
			const reel: MarqueurCarte = {
				lat: m.result.coordonnees.lat,
				lon: m.result.coordonnees.lon,
				type: 'reel',
				label: m.result.nom,
				paire: i + 1
			};
			if (!m.guess) return [reel];
			return [
				reel,
				{ lat: m.guess.lat, lon: m.guess.lon, type: 'guess', label: m.result.nom, paire: i + 1 }
			];
		})
	);

	async function chargerRound(): Promise<void> {
		chargement = true;
		erreur = false;
		place = null;
		guess = null;
		result = null;
		indicesMontres = [];
		try {
			const params = new URLSearchParams();
			if (regionParam) params.set('region', regionParam);
			if (mode === 'monument') params.set('categorie', 'MONUMENT');
			if (mode === 'lieu') params.set('categorie', 'LIEU');
			if (mode === 'street') params.set('mode', 'street');
			if (joues.length > 0) params.set('exclude', joues.join(','));
			const res = await fetch(`/api/round?${params}`);
			if (!res.ok) throw new Error(String(res.status));
			place = (await res.json()) as RoundPlace;
		} catch {
			erreur = true;
		} finally {
			chargement = false;
		}
	}

	async function soumettre(skip: boolean): Promise<void> {
		if (!place || result || enCours) return;
		if (!skip && !guess) return;
		enCours = true;
		try {
			const body: Record<string, unknown> = { id: place.id };
			if (skip) {
				body.skip = true;
			} else {
				body.lat = guess!.lat;
				body.lon = guess!.lon;
				body.hintsUsed = indicesMontres.length;
				if (timerActif && timerRef) body.timeMs = timerRef.tempsMs();
			}
			const res = await fetch('/api/guess', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(body)
			});
			if (!res.ok) throw new Error(String(res.status));
			result = (await res.json()) as GuessResult;
			joues = [...joues, place.id];
			if (estDefi) {
				defi.ajouter({ place, guess: skip ? null : guess, result });
			}
		} catch {
			erreur = true;
		} finally {
			enCours = false;
		}
	}

	function montrerIndice(): void {
		if (!place) return;
		const prochain = place.indices.find((i) => !indicesMontres.includes(i.texte));
		if (prochain) indicesMontres = [...indicesMontres, prochain.texte];
	}

	function suivant(): void {
		void chargerRound();
	}

	function montrerBilan(): void {
		bilan = true;
	}

	function rejouerDefi(): void {
		defi.reinitialiser();
		joues = [];
		bilan = false;
		void chargerRound();
	}

	/** Génère une image canvas téléchargeable : score total + régions jouées. */
	function partager(): void {
		const canvas = document.createElement('canvas');
		canvas.width = 1080;
		canvas.height = 1080;
		const ctx = canvas.getContext('2d');
		if (!ctx) return;

		// Fond sable + bandeau vert profond
		ctx.fillStyle = '#f5efe2';
		ctx.fillRect(0, 0, 1080, 1080);
		ctx.fillStyle = '#0b3d2e';
		ctx.fillRect(0, 0, 1080, 240);

		ctx.fillStyle = '#fffdf8';
		ctx.textAlign = 'center';
		ctx.font = '800 96px system-ui, sans-serif';
		ctx.fillText('JWE', 540, 130);
		ctx.font = '600 44px system-ui, sans-serif';
		ctx.fillText(t().modes.defi, 540, 200);

		// Score total
		ctx.fillStyle = '#0b3d2e';
		ctx.font = '800 150px system-ui, sans-serif';
		ctx.fillText(`${defi.total}`, 540, 420);
		ctx.fillStyle = '#5a6b62';
		ctx.font = '500 40px system-ui, sans-serif';
		ctx.fillText(t().defi.scoreTotal, 540, 480);

		// Manches : lieu, région, score
		let y = 580;
		for (const [i, m] of defi.manches.entries()) {
			ctx.fillStyle = i % 2 === 0 ? '#e3efe7' : '#f5efe2';
			ctx.fillRect(90, y - 44, 900, 74);
			ctx.fillStyle = '#22302a';
			ctx.textAlign = 'left';
			ctx.font = '600 34px system-ui, sans-serif';
			ctx.fillText(`${i + 1}. ${m.result.nom}`, 120, y);
			ctx.fillStyle = '#17624a';
			ctx.font = '500 30px system-ui, sans-serif';
			ctx.fillText(t().regions[m.result.region], 120, y + 34);
			ctx.textAlign = 'right';
			ctx.fillStyle = '#0b3d2e';
			ctx.font = '800 40px system-ui, sans-serif';
			ctx.fillText(`${m.result.score}`, 960, y + 8);
			y += 92;
		}

		ctx.fillStyle = '#5a6b62';
		ctx.textAlign = 'center';
		ctx.font = '500 30px system-ui, sans-serif';
		ctx.fillText('labola.o-k-i.net', 540, 1010);

		const a = document.createElement('a');
		a.href = canvas.toDataURL('image/png');
		a.download = 'jwe-defi.png';
		a.click();
	}

	onMount(() => {
		// Nouveau défi : on repart de zéro quand on arrive sur la première manche.
		if (estDefi && defi.termine) defi.reinitialiser();
		void chargerRound();
	});
</script>

<svelte:head>
	<title>{t().app.titre} — {t().modes[mode]}</title>
</svelte:head>

<div class="jeu">
	{#if bilan}
		<div class="bilan">
			<h1>{t().defi.bilan}</h1>
			<p class="total">
				<span class="valeur">{defi.total}</span>
				<span class="unite">{t().defi.scoreTotal}</span>
			</p>
			<div class="bilan-carte">
				<CarteRegions selectionnable={false} marqueurs={marqueursRecap} />
			</div>
			<ol class="recap">
				{#each defi.manches as m, i (m.place.id)}
					<li>
						<span class="r-nom">{i + 1}. {m.result.nom}</span>
						<span class="r-region">{t().regions[m.result.region]}</span>
						<span class="r-score">{m.result.score} {t().resultat.points}</span>
					</li>
				{/each}
			</ol>
			<div class="bilan-actions">
				<button type="button" class="btn btn-primaire" onclick={partager}>
					{t().defi.partager}
				</button>
				<button type="button" class="btn btn-secondaire" onclick={rejouerDefi}>
					{t().resultat.rejouer}
				</button>
				<a href="/" class="btn btn-tertiaire">{t().resultat.retourAccueil}</a>
			</div>
			<p class="legende">
				<span class="puce joueur" aria-hidden="true">●</span> {t().defi.taPosition} —
				<span class="puce reelle" aria-hidden="true">●</span> {t().defi.positionReelle}
			</p>
		</div>
	{:else if chargement}
		<div class="etat"><p>{t().jeu.charger}</p></div>
	{:else if erreur}
		<div class="etat">
			<p>{t().jeu.erreur}</p>
			<button type="button" class="btn btn-secondaire" onclick={() => void chargerRound()}>
				{t().jeu.reessayer}
			</button>
		</div>
	{:else if place}
		<div class="split" class:resultat={!!result}>
			<section class="panneau-photo">
				{#if result}
					<div class="resultat-scroll">
						<ResultPanel
							{result}
							creditPhoto={place.photo?.credit ?? place.credit}
							labelBouton={estDefi && defiTermine ? t().resultat.voirBilan : t().resultat.suivant}
							onsuivant={estDefi && defiTermine ? montrerBilan : suivant}
						/>
					</div>
				{:else if place.mapillaryId}
					<StreetPanel mapillaryId={place.mapillaryId} credit={place.credit} />
				{:else if place.photo}
					<PhotoPanel photo={place.photo} />
				{/if}
			</section>

			<section class="panneau-carte">
				<GameMap
					bind:guess
					real={result ? result.coordonnees : null}
					distanceKm={result ? result.distanceKm : null}
					interactive={!result}
					onvalidate={() => void soumettre(false)}
				/>
				{#if estDefi && !defiTermine}
					<span class="badge-manche">{t().jeu.round} {Math.min(mancheCourante, 5)} {t().jeu.sur} 5</span>
				{/if}
				{#if timerActif && !result}
					<div class="badge-timer">
						<TimerRing bind:this={timerRef} actif={!result} />
					</div>
				{/if}
			</section>
		</div>

		{#if !result}
			<div class="barre-actions">
				<div class="actions-secondaires">
					<button
						type="button"
						class="btn btn-tertiaire"
						onclick={montrerIndice}
						disabled={indicesMontres.length >= place.indices.length}
					>
						{t().jeu.indice}
						<span class="penalite">{t().jeu.indicePenalite}</span>
					</button>
					<button type="button" class="btn btn-secondaire" onclick={() => void soumettre(true)}>
						{t().jeu.passer}
					</button>
				</div>
				<button
					type="button"
					class="btn btn-primaire valider"
					disabled={!guess || enCours}
					onclick={() => void soumettre(false)}
				>
					{t().jeu.valider}
				</button>
			</div>
			{#if indicesMontres.length > 0}
				<aside class="indices" aria-live="polite">
					{#each indicesMontres as texte, i (texte)}
						<p class="indice"><strong>{t().jeu.indice} {i + 1}</strong> — {texte}</p>
					{/each}
				</aside>
			{/if}
			{#if !guess}
				<p class="aide-carte">{t().jeu.poserMarqueur}</p>
			{/if}
		{/if}
	{/if}
</div>

<style>
	.jeu {
		flex: 1;
		display: flex;
		flex-direction: column;
		min-height: 0;
	}

	.etat {
		flex: 1;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 1rem;
		color: var(--oki-encre-doux);
	}

	.split {
		flex: 1;
		display: flex;
		flex-direction: column;
		gap: 0.6rem;
		padding: 0.6rem;
		min-height: 0;
	}

	/* Mobile : photo 60 % haut, carte 40 % bas */
	.panneau-photo {
		flex: 0 0 58%;
		min-height: 0;
	}

	.split.resultat .panneau-photo {
		flex: 1 1 55%;
		overflow-y: auto;
	}

	.panneau-carte {
		position: relative;
		flex: 1;
		min-height: 220px;
	}

	.resultat-scroll {
		height: 100%;
		overflow-y: auto;
		background: var(--oki-blanc);
		border-radius: var(--oki-radius);
		box-shadow: var(--oki-ombre);
		padding: 1rem;
	}

	.badge-manche {
		position: absolute;
		top: 0.6rem;
		right: 0.6rem;
		background: rgba(255, 253, 248, 0.94);
		color: var(--oki-vert);
		border-radius: 999px;
		padding: 0.25rem 0.8rem;
		font-size: 0.82rem;
		font-weight: 700;
		box-shadow: var(--oki-ombre);
	}

	.badge-timer {
		position: absolute;
		top: 0.6rem;
		left: 3.4rem; /* à droite des boutons zoom */
	}

	/* Barre d'actions : fixe en zone du pouce (tiers inférieur) */
	.barre-actions {
		position: sticky;
		bottom: 0;
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 0.6rem;
		padding: 0.7rem 0.8rem calc(0.7rem + env(safe-area-inset-bottom));
		background: var(--oki-blanc);
		border-top: 1px solid var(--oki-sable-fonce);
	}

	.actions-secondaires {
		display: flex;
		gap: 0.5rem;
	}

	.actions-secondaires .btn {
		padding: 0.7rem 1rem;
		font-size: 0.92rem;
	}

	.penalite {
		font-size: 0.75rem;
		font-weight: 500;
		opacity: 0.8;
	}

	.valider {
		flex: 0 0 auto;
		padding: 0.9rem 1.4rem;
	}

	.indices {
		padding: 0 1rem 0.5rem;
	}

	.indice {
		margin: 0.25rem 0;
		background: var(--oki-bleu-doux);
		border-left: 4px solid var(--oki-bleu);
		border-radius: var(--oki-radius-petit);
		padding: 0.5rem 0.8rem;
		font-size: 0.95rem;
	}

	.aide-carte {
		margin: 0;
		padding: 0 1rem 0.6rem;
		text-align: center;
		font-size: 0.88rem;
		color: var(--oki-encre-doux);
	}

	/* Desktop : 50/50 */
	@media (min-width: 768px) {
		.split {
			flex-direction: row;
		}

		.panneau-photo,
		.split.resultat .panneau-photo {
			flex: 1 1 50%;
		}

		.panneau-carte {
			flex: 1 1 50%;
		}

		.barre-actions {
			justify-content: center;
			gap: 1.5rem;
		}
	}

	/* — Écran bilan du défi — */
	.bilan {
		flex: 1;
		width: 100%;
		max-width: 860px;
		margin: 0 auto;
		padding: 1.2rem 1rem 2rem;
		display: flex;
		flex-direction: column;
		gap: 1rem;
	}

	.bilan h1 {
		margin: 0;
		text-align: center;
		color: var(--oki-vert);
	}

	.total {
		margin: 0;
		text-align: center;
	}

	.total .valeur {
		font-size: 2.8rem;
		font-weight: 800;
		color: var(--oki-vert);
	}

	.total .unite {
		margin-left: 0.4rem;
		color: var(--oki-encre-doux);
	}

	.bilan-carte {
		width: 100%;
		max-width: 520px;
		margin: 0 auto;
	}

	.recap {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: 0.4rem;
	}

	.recap li {
		display: flex;
		align-items: baseline;
		gap: 0.6rem;
		background: var(--oki-blanc);
		border-radius: var(--oki-radius-petit);
		box-shadow: var(--oki-ombre);
		padding: 0.55rem 0.9rem;
	}

	.r-nom {
		font-weight: 700;
		color: var(--oki-vert);
	}

	.r-region {
		flex: 1;
		color: var(--oki-encre-doux);
		font-size: 0.9rem;
	}

	.r-score {
		font-weight: 800;
	}

	.bilan-actions {
		display: flex;
		flex-wrap: wrap;
		justify-content: center;
		gap: 0.7rem;
	}

	.legende {
		margin: 0;
		text-align: center;
		font-size: 0.85rem;
		color: var(--oki-encre-doux);
	}

	.puce.joueur {
		color: var(--oki-corail);
	}

	.puce.reelle {
		color: var(--oki-vert);
	}
</style>
