<script lang="ts">
	import { onDestroy, onMount } from 'svelte';
	import CharacterSearchInput from '$lib/components/CharacterSearchInput.svelte';
	import GuessHistoryTable from '$lib/components/GuessHistoryTable.svelte';
	import WinPanel from '$lib/components/WinPanel.svelte';
	import HintsPanel from '$lib/components/HintsPanel.svelte';
	import type { CharacterWithRelations } from '$lib/server/daily-character.js';
	import { language, t } from '$lib/i18n';

	export let data;

	let selectedCharacters: CharacterWithRelations[] = [];
	let currentCharacter: CharacterWithRelations | null = null;
	let isLoaded = false;
	let score = 0;
	type ArcFilterOption = { id: string; name: string };
	let allCharacters: CharacterWithRelations[] = [];
	let characters: CharacterWithRelations[] = [];
	let availableArcs: ArcFilterOption[] = [];
	let hasWon = false;
	let columnVisibility: Record<string, boolean> = {};
	let columnDisplayNames: Record<string, string> = {};

	// Character filters
	let characterFilters = {
		gender: [] as string[],
		hasHaki: false,
		hasDevilFruit: null as boolean | null, // null = all, true = with fruit, false = without fruit
		status: [] as string[],
		hasHeight: false,
		hasAge: false,
		hasOrigin: false,
		arcs: [] as string[]
	};

	let showOriginUnlock = false;
	let showFruitUnlock = false;
	let showAffiliationUnlock = false;
	let isGeckoMoriaWin = false;
	let originUnlockTimeout: ReturnType<typeof setTimeout> | null = null;
	let fruitUnlockTimeout: ReturnType<typeof setTimeout> | null = null;
	let affiliationUnlockTimeout: ReturnType<typeof setTimeout> | null = null;

	function clearUnlockTimeout(timeout: ReturnType<typeof setTimeout> | null) {
		if (timeout) {
			clearTimeout(timeout);
		}
	}

	function pulseUnlock(type: 'origin' | 'fruit' | 'affiliation') {
		if (type === 'origin') {
			clearUnlockTimeout(originUnlockTimeout);
			showOriginUnlock = true;
			originUnlockTimeout = setTimeout(() => {
				showOriginUnlock = false;
				originUnlockTimeout = null;
			}, 600);
			return;
		}

		if (type === 'fruit') {
			clearUnlockTimeout(fruitUnlockTimeout);
			showFruitUnlock = true;
			fruitUnlockTimeout = setTimeout(() => {
				showFruitUnlock = false;
				fruitUnlockTimeout = null;
			}, 600);
			return;
		}

		clearUnlockTimeout(affiliationUnlockTimeout);
		showAffiliationUnlock = true;
		affiliationUnlockTimeout = setTimeout(() => {
			showAffiliationUnlock = false;
			affiliationUnlockTimeout = null;
		}, 600);
	}

	function syncHintAvailability(previousGuessCount: number, nextGuessCount: number, animateUnlocks = false) {
		const nextOriginAvailable = nextGuessCount >= 5;
		const nextFruitAvailable = nextGuessCount >= 10;
		const nextAffiliationAvailable = nextGuessCount >= 15;

		if (animateUnlocks && nextOriginAvailable && previousGuessCount < 5) {
			pulseUnlock('origin');
		}

		if (animateUnlocks && nextFruitAvailable && previousGuessCount < 10) {
			pulseUnlock('fruit');
		}

		if (animateUnlocks && nextAffiliationAvailable && previousGuessCount < 15) {
			pulseUnlock('affiliation');
		}

		if (!nextOriginAvailable) {
			showOriginUnlock = false;
			clearUnlockTimeout(originUnlockTimeout);
			originUnlockTimeout = null;
		}

		if (!nextFruitAvailable) {
			showFruitUnlock = false;
			clearUnlockTimeout(fruitUnlockTimeout);
			fruitUnlockTimeout = null;
		}

		if (!nextAffiliationAvailable) {
			showAffiliationUnlock = false;
			clearUnlockTimeout(affiliationUnlockTimeout);
			affiliationUnlockTimeout = null;
		}

	}

	// Load from localStorage on mount
	onMount(() => {
		const storedScore = localStorage.getItem('infiniteScore');
		if (storedScore) {
			score = parseInt(storedScore, 10);
		}

		// Load column visibility from localStorage, fallback to server defaults
		const storedColumnVisibility = localStorage.getItem('infiniteColumnVisibility');
		if (storedColumnVisibility) {
			try {
				columnVisibility = JSON.parse(storedColumnVisibility);
			} catch (e) {
				console.error('Failed to parse column visibility', e);
				columnVisibility = data.columnVisibility || {};
			}
		} else {
			columnVisibility = data.columnVisibility || {};
		}

		// Load character filters from localStorage
		const storedFilters = localStorage.getItem('infiniteCharacterFilters');
		if (storedFilters) {
			try {
				characterFilters = JSON.parse(storedFilters);
				// Ensure all filter properties exist
				if (!characterFilters.arcs) {
					characterFilters.arcs = [];
				}
				if (typeof characterFilters.hasAge !== 'boolean') {
					characterFilters.hasAge = false;
				}
			} catch (e) {
				console.error('Failed to parse filters', e);
			}
		}

		// Load current character ID and history IDs from localStorage
		const storedCharacterId = localStorage.getItem('infiniteCurrentCharacterId');
		const storedHistoryIds = localStorage.getItem('infiniteSelectedCharacterIds');
		
		if (storedCharacterId && storedHistoryIds && characters.length > 0) {
			try {
				const charId = JSON.parse(storedCharacterId);
				const historyIds = JSON.parse(storedHistoryIds);
				
				// Find the character object by ID
				currentCharacter = characters.find((c: CharacterWithRelations) => c.id === charId) || null;
				
				// Find all character objects by their IDs
				selectedCharacters = historyIds
					.map((id: string) => characters.find((c: CharacterWithRelations) => c.id === id))
					.filter((c: CharacterWithRelations | undefined) => !!c) as CharacterWithRelations[];
				
				// If character not found, generate a new one
				if (!currentCharacter) {
					generateNewCharacter();
				}
			} catch (e) {
				console.error('Failed to parse character data', e);
				// If parsing fails, generate a new character
				generateNewCharacter();
			}
		} else {
			generateNewCharacter();
		}

		syncHintAvailability(0, selectedCharacters.length);
		isLoaded = true;
	});

	onDestroy(() => {
		clearUnlockTimeout(originUnlockTimeout);
		clearUnlockTimeout(fruitUnlockTimeout);
		clearUnlockTimeout(affiliationUnlockTimeout);
	});

	// Save score to localStorage whenever it changes
	$: if (isLoaded) {
		localStorage.setItem('infiniteScore', score.toString());
	}

	// Save column visibility to localStorage whenever it changes
	$: if (isLoaded) {
		localStorage.setItem('infiniteColumnVisibility', JSON.stringify(columnVisibility));
	}

	// Save character filters to localStorage whenever they change
	$: if (isLoaded) {
		localStorage.setItem('infiniteCharacterFilters', JSON.stringify(characterFilters));
	}

	// Save current character ID to localStorage whenever it changes
	$: if (isLoaded && currentCharacter) {
		localStorage.setItem('infiniteCurrentCharacterId', JSON.stringify(currentCharacter.id));
	}

	// Save selected character IDs to localStorage whenever it changes
	$: if (isLoaded) {
		const selectedIds = selectedCharacters.map((c: CharacterWithRelations) => c.id);
		localStorage.setItem('infiniteSelectedCharacterIds', JSON.stringify(selectedIds));
	}

	$: allCharacters = data.characters || [];
	$: isFrench = $language === 'fr';

	function getDisplayArcName(character: CharacterWithRelations, useFrench: boolean): string | null {
		if (useFrench && typeof character.frArcName === 'string' && character.frArcName.length > 0) {
			return character.frArcName;
		}

		return character.arcName;
	}

	// Extract unique arcs from all characters
	$: {
		const useFrench = isFrench;
		const arcMap = new Map<string, ArcFilterOption>(
			allCharacters
				.filter(
					(char: CharacterWithRelations): char is CharacterWithRelations & { arcId: string } =>
						typeof char.arcId === 'string' &&
						char.arcId.length > 0 &&
						typeof getDisplayArcName(char, useFrench) === 'string' &&
						getDisplayArcName(char, useFrench)!.length > 0
				)
				.map((char: CharacterWithRelations & { arcId: string }) => [
					char.arcId,
					{ id: char.arcId, name: getDisplayArcName(char, useFrench) as string }
				])
		);

		availableArcs = [...arcMap.values()].sort((a, b) => a.name.localeCompare(b.name));
	}
	
	// Filter characters based on selected filters
	$: characters = allCharacters.filter((char: CharacterWithRelations) => {
		// Gender filter
		if (characterFilters.gender.length > 0 && (char.gender == null || !characterFilters.gender.includes(char.gender))) {
			return false;
		}
		
		// Haki filter
		if (characterFilters.hasHaki && !(char.hakiObservation || char.hakiArmament || char.hakiConqueror)) {
			return false;
		}
		
		// Devil fruit filter
		if (characterFilters.hasDevilFruit !== null) {
			const hasDevil = char.devilFruitId !== null && char.devilFruitId !== undefined;
			if (characterFilters.hasDevilFruit !== hasDevil) {
				return false;
			}
		}
		
		// Status filter
		if (characterFilters.status.length > 0) {
			const normalizedStatus = normalizeStatus(char.status);
			if (!characterFilters.status.includes(normalizedStatus)) {
				return false;
			}
		}
		
		// Height filter
		if (characterFilters.hasHeight && (char.height === null || char.height === undefined)) {
			return false;
		}

		// Age filter
		if (characterFilters.hasAge && (char.age === null || char.age === undefined)) {
			return false;
		}
		
		// Origin filter
		if (characterFilters.hasOrigin && (char.origin === null || char.origin === undefined || char.origin === '')) {
			return false;
		}
		
		// Arc filter
		if (characterFilters.arcs.length > 0 && (char.arcId == null || !characterFilters.arcs.includes(char.arcId))) {
			return false;
		}
		
		return true;
	});
	$: {
		const currentCharacterId = currentCharacter?.id;
		hasWon = currentCharacterId != null && selectedCharacters.some(char => char.id === currentCharacterId);
	}
	$: if (hasWon && currentCharacter?.id === 'gecko_moria_gecko_moria') {
		isGeckoMoriaWin = true;
	} else if (!hasWon) {
		isGeckoMoriaWin = false;
	}
	$: columnDisplayNames = {
		status: $t.game.components.guessHistory.status,
		gender: $t.game.components.guessHistory.gender,
		affiliations: $t.game.components.guessHistory.affiliations,
		devilFruitType: $t.game.components.guessHistory.fruit,
		haki: $t.game.components.guessHistory.haki,
		bounty: $t.game.components.guessHistory.bounty,
		height: $t.game.components.guessHistory.height,
		age: $t.game.components.guessHistory.age,
		origin: $t.game.components.guessHistory.origin,
		arc: $t.game.components.guessHistory.arc
	};

	function generateNewCharacter() {
		if (characters.length === 0) return;
		currentCharacter = characters[Math.floor(Math.random() * characters.length)];
		syncHintAvailability(selectedCharacters.length, 0);
		selectedCharacters = [];
	}

	function handleCharacterSelect(character: CharacterWithRelations) {
		selectCharacter(character);
	}

	function selectCharacter(character: CharacterWithRelations) {
		const current = currentCharacter;
		if (!current) {
			return;
		}

		const previousGuessCount = selectedCharacters.length;
		selectedCharacters = [character, ...selectedCharacters];
		syncHintAvailability(previousGuessCount, selectedCharacters.length, isLoaded);

		// Check if player won
		if (character.id === current.id) {
			// Increment score (saved to localStorage via reactive statement)
			score++;
			// Don't auto-generate next character - wait for user to click "Recommencer"
		}
	}

	function nextCharacter() {
		generateNewCharacter();
	}

	function resetScore() {
		score = 0;
		selectedCharacters = [];
		generateNewCharacter();
		// Clear localStorage for current character and history
		localStorage.removeItem('infiniteCurrentCharacterId');
		localStorage.removeItem('infiniteSelectedCharacterIds');
	}

	function toggleColumnVisibility(column: string) {
		columnVisibility[column] = !columnVisibility[column];
		columnVisibility = columnVisibility; // Trigger reactivity
	}

	function revealAnswer() {
		if (!currentCharacter) {
			return;
		}

		// Reset score (strike)
		score = 0;
		// Add the current character as the correct answer
		const previousGuessCount = selectedCharacters.length;
		selectedCharacters = [currentCharacter, ...selectedCharacters];
		syncHintAvailability(previousGuessCount, selectedCharacters.length, isLoaded);
	}

	function toggleGenderFilter(gender: string) {
		if (characterFilters.gender.includes(gender)) {
			characterFilters.gender = characterFilters.gender.filter(g => g !== gender);
		} else {
			characterFilters.gender = [...characterFilters.gender, gender];
		}
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function toggleStatusFilter(status: string) {
		if (characterFilters.status.includes(status)) {
			characterFilters.status = characterFilters.status.filter(s => s !== status);
		} else {
			characterFilters.status = [...characterFilters.status, status];
		}
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function toggleHakiFilter() {
		characterFilters.hasHaki = !characterFilters.hasHaki;
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function toggleDevilFruitFilter() {
		if (characterFilters.hasDevilFruit === null) {
			characterFilters.hasDevilFruit = true;
		} else if (characterFilters.hasDevilFruit === true) {
			characterFilters.hasDevilFruit = false;
		} else {
			characterFilters.hasDevilFruit = null;
		}
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function toggleHeightFilter() {
		characterFilters.hasHeight = !characterFilters.hasHeight;
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function toggleAgeFilter() {
		characterFilters.hasAge = !characterFilters.hasAge;
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function toggleOriginFilter() {
		characterFilters.hasOrigin = !characterFilters.hasOrigin;
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function toggleArcFilter(arcId: string) {
		if (characterFilters.arcs.includes(arcId)) {
			characterFilters.arcs = characterFilters.arcs.filter(a => a !== arcId);
		} else {
			characterFilters.arcs = [...characterFilters.arcs, arcId];
		}
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function clearAllFilters() {
		characterFilters = {
			gender: [],
			hasHaki: false,
			hasDevilFruit: null,
			status: [],
			hasHeight: false,
			hasAge: false,
			hasOrigin: false,
			arcs: []
		};
		// Regenerate character with new filters
		if (!hasWon) {
			generateNewCharacter();
		}
	}

	function normalizeStatus(status: unknown): string {
		if (status == null) {
			return 'Unknown';
		}

		if (typeof status !== 'string') {
			return String(status);
		}

		const value = status.trim();
		if (value === '') {
			return 'Unknown';
		}

		switch (value.toLowerCase()) {
			case 'alive':
				return 'Alive';
			case 'dead':
			case 'deceased':
				return 'Dead';
			case 'unknown':
			case 'inconnu':
			case '-':
				return 'Unknown';
			default:
				return value;
		}
	}
</script>

<svelte:head>
	<title>{$t.game.infinite.metaTitle}</title>
	<style>
		@keyframes shadow-pulse {
			0% {
				text-shadow:
					0 0 20px rgba(0, 0, 0, 0.5),
					0 0 40px rgba(50, 50, 50, 0.8);
				opacity: 1;
			}
			50% {
				text-shadow:
					0 0 60px rgba(0, 0, 0, 0.9),
					0 0 100px rgba(30, 30, 30, 1),
					inset 0 0 50px rgba(0, 0, 0, 0.7);
				opacity: 0.9;
			}
			100% {
				text-shadow:
					0 0 20px rgba(0, 0, 0, 0.5),
					0 0 40px rgba(50, 50, 50, 0.8);
				opacity: 1;
			}
		}
		.gecko-moria-effect {
			animation: shadow-pulse 1.5s ease-in-out infinite;
		}
		@keyframes moria-chaos {
			0% {
				transform: rotate(0deg) scale(1);
				filter: invert(0%) hue-rotate(0deg) blur(0px);
			}
			10% {
				transform: rotate(15deg) scale(1.02);
				filter: invert(30%) hue-rotate(45deg) blur(2px);
			}
			20% {
				transform: rotate(-10deg) scale(0.98);
				filter: invert(60%) hue-rotate(90deg) blur(1px);
			}
			30% {
				transform: rotate(25deg) scale(1.05);
				filter: invert(100%) hue-rotate(180deg) blur(3px);
			}
			40% {
				transform: rotate(-20deg) scale(0.95);
				filter: invert(80%) hue-rotate(270deg) blur(2px);
			}
			50% {
				transform: rotate(30deg) scale(1.08);
				filter: invert(100%) hue-rotate(0deg) blur(4px);
			}
			60% {
				transform: rotate(-25deg) scale(0.92);
				filter: invert(70%) hue-rotate(90deg) blur(2px);
			}
			70% {
				transform: rotate(20deg) scale(1.03);
				filter: invert(50%) hue-rotate(180deg) blur(3px);
			}
			80% {
				transform: rotate(-15deg) scale(1.01);
				filter: invert(80%) hue-rotate(270deg) blur(1px);
			}
			100% {
				transform: rotate(360deg) scale(1);
				filter: invert(0%) hue-rotate(360deg) blur(0px);
			}
		}
		.moria-screen-chaos {
			animation: moria-chaos 4s ease-in-out;
		}
	</style>
</svelte:head>

<main
	class="relative min-h-screen overflow-hidden bg-slate-950 text-slate-100 {isGeckoMoriaWin
		? 'moria-screen-chaos'
		: ''}"
>
	<div
		class="absolute inset-0 bg-linear-to-br from-slate-950/85 via-slate-900/60 to-slate-950/80"
	></div>
	<div
		class="absolute inset-0 bg-[radial-gradient(circle_at_top,rgba(255,215,84,0.35),transparent_55%)] opacity-20 mix-blend-screen"
	></div>

	<div class="relative mx-auto flex min-h-screen w-full max-w-6xl flex-col px-6 py-8 sm:py-10">
		<header class="flex w-full flex-col items-start gap-6">
			<div class="flex w-full items-center justify-between gap-4">
				<div>
					<h1 class="text-3xl font-black tracking-[0.25em] text-amber-50 uppercase sm:text-5xl">
						{$t.game.infinite.title}
					</h1>
					<p class="mt-2 text-2xl font-bold text-amber-300">{$t.game.infinite.score}: {score}</p>
				</div>
				{#if score > 0}
					<button
						class="rounded-full border border-amber-200/40 bg-transparent px-5 py-3 text-sm font-semibold text-amber-100 transition hover:border-amber-200 hover:text-amber-50"
						onclick={resetScore}
					>
						{$t.game.infinite.resetScore}
					</button>
				{/if}
			</div>
			<p class="max-w-2xl text-base text-slate-200 sm:text-lg">
				{$t.game.infinite.description}
			</p>
		</header>

		<section class="mt-10 grid gap-6">
			{#if currentCharacter}
				{#if hasWon}
					<div>
						<WinPanel selectedCharacter={currentCharacter} {selectedCharacters} {isGeckoMoriaWin} />
						<button
							type="button"
							onclick={nextCharacter}
							class="mt-4 w-full rounded-full bg-emerald-500 px-6 py-2 text-sm font-semibold text-white transition hover:bg-emerald-600"
						>
							{$t.game.infinite.nextCharacter}
						</button>
					</div>
				{:else}
					{#if selectedCharacters.length > 0}
						<HintsPanel
							dailyCharacter={currentCharacter}
							{selectedCharacters}
							{showOriginUnlock}
							{showFruitUnlock}
							{showAffiliationUnlock}
						/>
						<div class="mt-2 flex justify-center">
							<button
								type="button"
								onclick={revealAnswer}
								class="rounded-lg border border-red-600/40 bg-red-900/20 px-4 py-2 text-sm text-red-300 transition hover:border-red-500 hover:bg-red-900/40 hover:text-red-200"
							>
								{$t.game.infinite.revealAnswer}
							</button>
						</div>
					{/if}
					<CharacterSearchInput
						{characters}
						{selectedCharacters}
						onSelect={handleCharacterSelect}
					/>
				{/if}
			{:else}
				<div
					class="rounded-3xl border border-white/10 bg-white/5 p-6 shadow-[0_24px_60px_rgba(0,0,0,0.45)] backdrop-blur"
				>
					<p class="text-center text-slate-300">{$t.game.infinite.loadingCharacter}</p>
				</div>
			{/if}
		</section>

		{#if currentCharacter}
			<GuessHistoryTable
				{selectedCharacters}
				dailyCharacter={currentCharacter}
				{columnVisibility}
			/>

			<!-- Character Filters -->
			<section class="mt-6">
				<div class="rounded-2xl border border-white/10 bg-white/5 p-3 backdrop-blur sm:p-4">
					<div class="mb-3 flex items-center justify-between gap-3">
						<h3 class="text-xs font-semibold tracking-[0.2em] text-amber-200 uppercase">
							{$t.game.infinite.filtersTitle}
						</h3>
						{#if characterFilters.gender.length > 0 || characterFilters.hasHaki || characterFilters.hasDevilFruit !== null || characterFilters.status.length > 0 || characterFilters.hasHeight || characterFilters.hasAge || characterFilters.hasOrigin || characterFilters.arcs.length > 0}
							<button
								type="button"
								onclick={clearAllFilters}
								class="text-xs text-red-300 transition hover:text-red-200"
							>
								{$t.game.infinite.clearFilters}
							</button>
						{/if}
					</div>

					<div class="space-y-3">
						<!-- Gender Filter -->
						<div>
							<p class="mb-2 text-xs text-slate-400">{$t.game.infinite.filterGender}</p>
							<div class="flex flex-wrap gap-2">
								{#each ['Male', 'Female'] as gender (gender)}
									<button
										type="button"
										onclick={() => toggleGenderFilter(gender)}
										class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.gender.includes(
											gender
										)
											? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
											: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
									>
										{gender === 'Male' ? $t.game.infinite.male : $t.game.infinite.female}
									</button>
								{/each}
							</div>
						</div>

						<!-- Status Filter -->
						<div>
							<p class="mb-2 text-xs text-slate-400">{$t.game.infinite.filterStatus}</p>
							<div class="flex flex-wrap gap-2">
								{#each ['Alive', 'Dead', 'Unknown'] as status (status)}
									<button
										type="button"
										onclick={() => toggleStatusFilter(status)}
										class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.status.includes(
											status
										)
											? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
											: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
									>
										{status === 'Alive' ? $t.game.infinite.alive : status === 'Dead' ? $t.game.infinite.dead : $t.game.infinite.unknown}
									</button>
								{/each}
							</div>
						</div>

						<!-- Haki Filter -->
						<div>
							<p class="mb-2 text-xs text-slate-400">{$t.game.infinite.filterAbilities}</p>
							<div class="flex flex-wrap gap-2">
								<button
									type="button"
									onclick={toggleHakiFilter}
									class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.hasHaki
										? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
										: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
								>
									{$t.game.infinite.hasHaki}
								</button>
								<button
									type="button"
									onclick={toggleDevilFruitFilter}
									class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.hasDevilFruit ===
									true
										? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
										: characterFilters.hasDevilFruit === false
											? 'border-purple-300/50 bg-purple-300/10 text-purple-100 hover:bg-purple-300/20'
											: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
								>
									{characterFilters.hasDevilFruit === null
										? $t.game.infinite.fruitAll
										: characterFilters.hasDevilFruit
											? $t.game.infinite.withFruit
											: $t.game.infinite.withoutFruit}
								</button>
							</div>
						</div>

						<!-- Informations Filter -->
						<div>
							<p class="mb-2 text-xs text-slate-400">{$t.game.infinite.filterInformation}</p>
							<div class="flex flex-wrap gap-2">
								<button
									type="button"
									onclick={toggleHeightFilter}
									class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.hasHeight
										? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
										: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
								>
									{$t.game.infinite.heightDefined}
								</button>
								<button
									type="button"
									onclick={toggleAgeFilter}
									class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.hasAge
										? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
										: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
								>
									{$t.game.infinite.ageDefined}
								</button>
								<button
									type="button"
									onclick={toggleOriginFilter}
									class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.hasOrigin
										? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
										: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
								>
									{$t.game.infinite.originDefined}
								</button>
							</div>
						</div>

						<!-- Arc Filter -->
						<div>
							<p class="mb-2 text-xs text-slate-400">{$t.game.infinite.filterArcs}</p>
							<div class="flex flex-wrap gap-2">
								{#each availableArcs as arc (arc.id)}
									<button
										type="button"
										onclick={() => toggleArcFilter(arc.id)}
										class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {characterFilters.arcs.includes(
											arc.id
										)
											? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
											: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
									>
										{arc.name}
									</button>
								{/each}
							</div>
						</div>

						<p class="mt-2 text-xs text-slate-500">
							{characters.length} {characters.length > 1 ? $t.game.infinite.availableCharactersPlural : $t.game.infinite.availableCharactersSingular}
						</p>
					</div>
				</div>
			</section>

			<!-- Column Visibility Toggle -->
			<section class="mt-6">
				<div class="rounded-2xl border border-white/10 bg-white/5 p-3 backdrop-blur sm:p-4">
					<div class="mb-3 flex items-center justify-between gap-3">
						<h3 class="text-xs font-semibold tracking-[0.2em] text-amber-200 uppercase">
							{$t.game.infinite.columnsTitle}
						</h3>
						<p class="text-xs text-slate-400">
							{Object.values(columnVisibility).filter(Boolean).length}/{Object.keys(
								columnVisibility
							).length}
						</p>
					</div>
					<div class="flex flex-wrap gap-2">
						{#each Object.entries(columnVisibility) as [column, isVisible] (column)}
							<button
								type="button"
								onclick={() => toggleColumnVisibility(column)}
								class="rounded-full border px-2.5 py-1 text-xs font-medium transition-colors {isVisible
									? 'border-amber-300/50 bg-amber-300/10 text-amber-100 hover:bg-amber-300/20'
									: 'border-white/20 bg-slate-900/40 text-slate-400 hover:bg-slate-900/60'}"
							>
								{columnDisplayNames[column] || column.replace(/([A-Z])/g, ' $1').trim()}
							</button>
						{/each}
					</div>
				</div>
			</section>
		{/if}
	</div>
</main>

<style>
	@keyframes hint-unlock {
		0% {
			box-shadow: 0 0 0 rgba(251, 146, 60, 0);
		}
		50% {
			box-shadow: 0 0 20px rgba(251, 146, 60, 0.8);
		}
		100% {
			box-shadow: 0 0 0 rgba(251, 146, 60, 0);
		}
	}
	:global(.hint-unlocking) {
		animation: hint-unlock 0.6s ease-out;
	}
</style>
