<script lang="ts">
    import type { ExtendedEvent } from "@components/types/event";
    import type { Team } from "@components/types/team";
    import { eventRepo } from "@components/repo/event";
    import { fightRepo } from "@components/repo/fight";
    import { gamemodes, maps } from "@components/stores/stores";
    import { Button } from "@components/ui/button";
    import { Card } from "@components/ui/card";
    import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte";
    import { Label } from "@components/ui/label";
    import { Select, SelectContent, SelectItem, SelectTrigger } from "@components/ui/select";
    import { Slider } from "@components/ui/slider";
    import { fromAbsolute } from "@internationalized/date";
    import dayjs from "dayjs";
    import { Plus, Shuffle } from "lucide-svelte";
    import { replace } from "svelte-spa-router";

    let { data }: { data: ExtendedEvent } = $props();

    // --- Seeding model: support teams, group results, unknown placeholders ---
    interface SeedTeamSlot {
        kind: "TEAM";
        id: number;
    }
    interface SeedGroupSlot {
        kind: "GROUP";
        groupId: number;
        place: number;
    }
    interface SeedUnknownSlot {
        kind: "UNKNOWN";
        uid: number;
    }
    interface SeedFightSlot {
        kind: "FIGHT";
        fightId: number;
        place: 0 | 1;
    } // 0 winner, 1 loser
    type SeedSlot = SeedTeamSlot | SeedGroupSlot | SeedUnknownSlot | SeedFightSlot;

    let seedSlots = $state<SeedSlot[]>(data.teams.map((t) => ({ kind: "TEAM", id: t.id })));
    const teams = $derived(new Map<number, Team>(data.teams.map((t) => [t.id, t])));
    let unknownCounter = 1;

    function shuffleTeams() {
        const teamIndices = seedSlots.map((v, i) => ({ v, i })).filter((x) => x.v.kind === "TEAM");
        const shuffledIds = teamIndices.map((x) => (x.v as SeedTeamSlot).id).sort(() => Math.random() - 0.5);
        let p = 0;
        seedSlots = seedSlots.map((slot) => (slot.kind === "TEAM" ? { kind: "TEAM", id: shuffledIds[p++] } : slot));
    }

    function moveSlot(index: number, dir: -1 | 1) {
        const newIndex = index + dir;
        if (newIndex < 0 || newIndex >= seedSlots.length) return;
        const copy = [...seedSlots];
        const [item] = copy.splice(index, 1);
        copy.splice(newIndex, 0, item);
        seedSlots = copy;
    }
    function removeSlot(index: number) {
        seedSlots = seedSlots.filter((_, i) => i !== index);
    }
    function addUnknown() {
        seedSlots = [...seedSlots, { kind: "UNKNOWN", uid: unknownCounter++ }];
    }
    let selectedAddTeam = $state<number>(data.teams[0]?.id ?? 0);
    function addTeam() {
        if (selectedAddTeam !== undefined) seedSlots = [...seedSlots, { kind: "TEAM", id: selectedAddTeam }];
    }
    let selectedGroup = $state<number | null>(data.groups[0]?.id ?? null);
    let selectedGroupPlace = $state<number>(0);
    function addGroupPlace() {
        if (selectedGroup != null) seedSlots = [...seedSlots, { kind: "GROUP", groupId: selectedGroup, place: selectedGroupPlace }];
    }

    // Fight seed selection
    let selectedFight = $state<number | null>(data.fights[0]?.id ?? null);
    let selectedFightPlace = $state<0 | 1>(0);
    function addFightPlace() {
        if (selectedFight != null) seedSlots = [...seedSlots, { kind: "FIGHT", fightId: selectedFight, place: selectedFightPlace }];
    }

    // Config inputs
    let startTime = $state(fromAbsolute(data.event.start, "Europe/Berlin"));
    let roundTime = $state(30); // minutes per round
    let startDelay = $state(30); // seconds between fights inside round
    let gamemode = $state("");
    let map = $state("");

    // Gamemode / Map selection stores
    let selectableGamemodes = $derived($gamemodes.map((g) => ({ name: g, value: g })).sort((a, b) => a.name.localeCompare(b.name)));
    let mapsStore = $derived(maps(gamemode));
    let selectableMaps = $derived($mapsStore.map((m) => ({ name: m, value: m })).sort((a, b) => a.name.localeCompare(b.name)));

    // Derived: bracket rounds preview
    interface BracketFightPreview {
        blue: SeedSlot;
        red: SeedSlot;
    }
    type BracketRoundPreview = BracketFightPreview[];

    function buildBracketSeeds(order: SeedSlot[]): BracketRoundPreview[] {
        const n = order.length;
        if (n < 2) return [];
        // Require power of two for now; simplest implementation
        if ((n & (n - 1)) !== 0) return [];
        let rounds: BracketRoundPreview[] = [];
        let round: BracketRoundPreview = [];
        for (let i = 0; i < order.length; i += 2) round.push({ blue: order[i], red: order[i + 1] });
        rounds.push(round);
        // Higher rounds placeholders using first team from each prior pairing as seed representative
        let prevWinners = round.map((fight) => fight.blue);
        while (prevWinners.length > 1) {
            const nextRound: BracketRoundPreview = [];
            for (let i = 0; i < prevWinners.length; i += 2) {
                nextRound.push({ blue: prevWinners[i], red: prevWinners[i + 1] });
            }
            rounds.push(nextRound);
            prevWinners = nextRound.map((f) => f.blue);
        }
        return rounds;
    }

    let bracketRounds = $derived(buildBracketSeeds(seedSlots));

    let generateDisabled = $derived(gamemode !== "" && map !== "" && bracketRounds.length > 0 && seedSlots.length >= 2);

    async function generateBracket() {
        if (!generateDisabled) return;
        const eventId = data.event.id;
        // create elimination group
        const group = await $eventRepo.createGroup(eventId, { name: "Elimination", type: "ELIMINATION_STAGE" });

        // Create fights round by round & keep ids for relation wiring
        const fightIdsByRound: number[][] = [];
        function fallbackTeamId(slot: SeedSlot): number {
            // If this seed is a relation (GROUP or FIGHT), use -1 as requested
            if (slot.kind === "GROUP" || slot.kind === "FIGHT") return -1;
            if (slot.kind === "TEAM") return slot.id;
            // UNKNOWN stays as a concrete placeholder team or -1? Keep concrete team to avoid backend errors.
            return data.teams[0].id;
        }
        for (let r = 0; r < bracketRounds.length; r++) {
            const round = bracketRounds[r];
            const ids: number[] = [];
            for (let i = 0; i < round.length; i++) {
                const pair = round[i];
                let finalMap = map;
                if (finalMap === "%random%" && selectableMaps.length > 0) finalMap = selectableMaps[Math.floor(Math.random() * selectableMaps.length)].value;
                const fight = await $fightRepo.createFight(eventId, {
                    blueTeam: fallbackTeamId(pair.blue),
                    redTeam: fallbackTeamId(pair.red),
                    group: group.id,
                    map: finalMap,
                    spectatePort: null,
                    spielmodus: gamemode,
                    start: dayjs(
                        startTime
                            .copy()
                            .add({ minutes: roundTime * r })
                            .add({ seconds: startDelay * i })
                            .toDate()
                    ),
                });
                if (pair.blue.kind === "GROUP") await $eventRepo.createRelation(eventId, { fightId: fight.id, team: "BLUE", fromType: "GROUP", fromId: pair.blue.groupId, fromPlace: pair.blue.place });
                if (pair.red.kind === "GROUP") await $eventRepo.createRelation(eventId, { fightId: fight.id, team: "RED", fromType: "GROUP", fromId: pair.red.groupId, fromPlace: pair.red.place });
                if (pair.blue.kind === "FIGHT") await $eventRepo.createRelation(eventId, { fightId: fight.id, team: "BLUE", fromType: "FIGHT", fromId: pair.blue.fightId, fromPlace: pair.blue.place });
                if (pair.red.kind === "FIGHT") await $eventRepo.createRelation(eventId, { fightId: fight.id, team: "RED", fromType: "FIGHT", fromId: pair.red.fightId, fromPlace: pair.red.place });
                ids.push(fight.id);
            }
            fightIdsByRound.push(ids);
        }

        // Wire relations: for each fight in rounds >0, reference winners of two source fights from previous round
        for (let r = 1; r < fightIdsByRound.length; r++) {
            const prev = fightIdsByRound[r - 1];
            const current = fightIdsByRound[r];
            for (let i = 0; i < current.length; i++) {
                const targetFightId = current[i];
                const srcA = prev[i * 2];
                const srcB = prev[i * 2 + 1];
                // Winner assumed place 1
                await $eventRepo.createRelation(eventId, {
                    fightId: targetFightId,
                    team: "BLUE",
                    fromType: "FIGHT",
                    fromId: srcA,
                    fromPlace: 1,
                });
                await $eventRepo.createRelation(eventId, {
                    fightId: targetFightId,
                    team: "RED",
                    fromType: "FIGHT",
                    fromId: srcB,
                    fromPlace: 1,
                });
            }
        }

        // Redirect back to event view
        await replace("#/event/" + eventId);
    }

    // Helpers for template rendering with TS type guards
    function isTeam(slot: SeedSlot): slot is SeedTeamSlot {
        return slot.kind === "TEAM";
    }
    function isGroup(slot: SeedSlot): slot is SeedGroupSlot {
        return slot.kind === "GROUP";
    }
    function slotLabel(slot: SeedSlot): string {
        if (isTeam(slot)) return teams.get(slot.id)?.name ?? "Team";
        if (isGroup(slot)) {
            const gname = data.groups.find((g) => g.id === slot.groupId)?.name ?? "?";
            return `(Grp ${gname} Platz ${slot.place + 1})`;
        }
        if (slot.kind === "FIGHT") {
            const f = data.fights.find((x) => x.id === slot.fightId);
            const when = f ? new Date(f.start).toLocaleTimeString("de-DE", { timeStyle: "short" }) : "?";
            const vs = f ? `${f.blueTeam.kuerzel} vs. ${f.redTeam.kuerzel}` : "Kampf";
            return `${slot.place === 0 ? "Gewinner" : "Verlierer"} von ${vs} (${when})`;
        }
        return "???";
    }
</script>

<Card class="p-4 mb-4">
    <div class="flex justify-between items-center mb-4">
        <h2 class="text-xl font-bold">Single Elimination Bracket</h2>
        <div class="flex gap-2">
            <Button onclick={shuffleTeams} aria-label="Shuffle Teams"><Shuffle size={16} /> Shuffle</Button>
        </div>
    </div>
    {#if seedSlots.length < 2}
        <p class="text-gray-400">Mindestens zwei Seeds benötigt.</p>
    {:else if bracketRounds.length === 0}
        <p class="text-yellow-400">Anzahl der Seeds muss eine Zweierpotenz sein (2,4,8,16,...). Aktuell: {seedSlots.length}</p>
    {/if}
    <div class="grid md:grid-cols-2 gap-4">
        <div class="space-y-4">
            <div>
                <Label>Seeds / Reihenfolge</Label>
                <ul class="mt-2 space-y-1">
                    {#each seedSlots as slot, i (i)}
                        <li class="flex items-center gap-2 text-sm">
                            <span class="w-6 text-right">{i + 1}.</span>
                            <span class="flex-1 truncate">{slotLabel(slot)}</span>
                            <div class="flex gap-1">
                                <Button size="sm" onclick={() => moveSlot(i, -1)} disabled={i === 0}>↑</Button>
                                <Button size="sm" onclick={() => moveSlot(i, 1)} disabled={i === seedSlots.length - 1}>↓</Button>
                                <Button size="sm" variant="destructive" onclick={() => removeSlot(i)}>✕</Button>
                            </div>
                        </li>
                    {/each}
                </ul>
            </div>
            <div class="space-y-2">
                <Label>Seed hinzufügen</Label>
                <div class="flex flex-col gap-2">
                    <div class="flex flex-wrap gap-2 items-center">
                        <select class="bg-gray-800 border border-gray-700 rounded px-2 py-1" bind:value={selectedAddTeam}>
                            {#each data.teams as t}<option value={t.id}>{t.name}</option>{/each}
                        </select>
                        <Button size="sm" onclick={addTeam}>Team</Button>
                        <Button size="sm" onclick={addUnknown}>???</Button>
                    </div>
                    <div class="flex flex-wrap gap-2 items-center">
                        {#if data.groups.length > 0}
                            <select class="bg-gray-800 border border-gray-700 rounded px-2 py-1" bind:value={selectedGroup}>
                                {#each data.groups as g}<option value={g.id}>{g.name}</option>{/each}
                            </select>
                            <select class="bg-gray-800 border border-gray-700 rounded px-2 py-1" bind:value={selectedGroupPlace}>
                                {#each Array(16) as _, idx}<option value={idx}>{idx + 1}. Platz</option>{/each}
                            </select>
                            <Button size="sm" onclick={addGroupPlace}>Gruppenplatz</Button>
                        {/if}
                    </div>
                    <div class="flex flex-wrap gap-2 items-center">
                        {#if data.fights.length > 0}
                            <select class="bg-gray-800 border border-gray-700 rounded px-2 py-1" bind:value={selectedFight}>
                                {#each data.fights as f}
                                    <option value={f.id}>{new Date(f.start).toLocaleTimeString("de-DE", { timeStyle: "short" })}: {f.blueTeam.kuerzel} vs. {f.redTeam.kuerzel}</option>
                                {/each}
                            </select>
                            <select class="bg-gray-800 border border-gray-700 rounded px-2 py-1" bind:value={selectedFightPlace}>
                                <option value={0}>Gewinner</option>
                                <option value={1}>Verlierer</option>
                            </select>
                            <Button size="sm" onclick={addFightPlace}>Kampfplatz</Button>
                        {/if}
                    </div>
                </div>
                <p class="text-xs text-gray-500">Gruppen- oder Kampfplätze erzeugen Relationen beim Generieren. ??? bleibt Platzhalter.</p>
            </div>
        </div>
        <div>
            <Label>Startzeit</Label>
            <DateTimePicker bind:value={startTime} />
            <div class="mt-4">
                <Label>Rundenzeit: {roundTime}m</Label>
                <Slider type="single" bind:value={roundTime} step={5} min={5} max={60} />
            </div>
            <div class="mt-4">
                <Label>Startverzögerung: {startDelay}s</Label>
                <Slider type="single" bind:value={startDelay} step={5} min={0} max={60} />
            </div>
            <div class="mt-4">
                <Label>Spielmodus</Label>
                <Select type="single" bind:value={gamemode}>
                    <SelectTrigger>{gamemode}</SelectTrigger>
                    <SelectContent>
                        {#each selectableGamemodes as gm}
                            <SelectItem value={gm.value}>{gm.name}</SelectItem>
                        {/each}
                    </SelectContent>
                </Select>
            </div>
            <div class="mt-4">
                <Label>Map</Label>
                <Select type="single" bind:value={map}>
                    <SelectTrigger>{map}</SelectTrigger>
                    <SelectContent>
                        <SelectItem value="%random%">Zufällige Map</SelectItem>
                        {#each selectableMaps as mp}
                            <SelectItem value={mp.value}>{mp.name}</SelectItem>
                        {/each}
                    </SelectContent>
                </Select>
            </div>
        </div>
    </div>
    <div class="mt-6">
        <Label>Vorschau</Label>
        {#if bracketRounds.length > 0}
            <div class="flex gap-8 overflow-x-auto mt-2">
                {#each bracketRounds as round, r}
                    <div>
                        <h3 class="font-semibold mb-2">Runde {r + 1}</h3>
                        <ul class="space-y-1">
                            {#each round as fight, i}
                                <li class="p-2 border border-gray-700 rounded text-sm">
                                    <span class="text-gray-400"
                                        >{new Intl.DateTimeFormat("de-DE", { hour: "2-digit", minute: "2-digit" }).format(
                                            startTime
                                                .copy()
                                                .add({ minutes: roundTime * r, seconds: startDelay * i })
                                                .toDate()
                                        )}</span
                                    >
                                    : {slotLabel(fight.blue)} &nbsp;vs.&nbsp; {slotLabel(fight.red)}
                                </li>
                            {/each}
                        </ul>
                    </div>
                {/each}
            </div>
        {/if}
    </div>
    <Button class="!p-4 fixed bottom-4 right-4" disabled={!generateDisabled} onclick={generateBracket} aria-label="Bracket generieren">
        <Plus />
    </Button>
</Card>

<!-- no component-scoped styles needed -->
