<script lang="ts">
    import type {
        ExtendedEvent,
        EventFight,
        ResponseGroups,
        ResponseRelation,
    } from "@type/event.ts";
    import type { DoubleEleminationViewConfig } from "./types";
    import EventCard from "./EventCard.svelte";
    import EventFightChip from "./EventFightChip.svelte";
    import { onMount, onDestroy, tick } from "svelte";
    import { fightConnector } from "./connections.svelte.ts";

    const {
        event,
        config,
    }: { event: ExtendedEvent; config: DoubleEleminationViewConfig } = $props();

    const defaultGroup: ResponseGroups = {
        id: -1,
        name: "Double Elimination",
        pointsPerWin: 0,
        pointsPerLoss: 0,
        pointsPerDraw: 0,
        type: "ELIMINATION_STAGE",
        points: null,
    };

    function indexRelations(
        ev: ExtendedEvent,
    ): Map<number, ResponseRelation[]> {
        const map = new Map<number, ResponseRelation[]>();
        for (const rel of ev.relations) {
            const list = map.get(rel.fight) ?? [];
            list.push(rel);
            map.set(rel.fight, list);
        }
        return map;
    }

    const relationsByFight = indexRelations(event);
    const fightMap = new Map<number, EventFight>(
        event.fights.map((f) => [f.id, f]),
    );

    function collectBracket(startFinalId: number): EventFight[][] {
        const finalFight = fightMap.get(startFinalId);
        if (!finalFight) return [];
        const bracketGroupId = finalFight.group?.id ?? null;
        const stages: EventFight[][] = [];
        let layer: EventFight[] = [finalFight];
        const visited = new Set<number>([finalFight.id]);
        while (layer.length) {
            stages.push(layer);
            const next: EventFight[] = [];
            for (const fight of layer) {
                const rels = relationsByFight.get(fight.id) ?? [];
                for (const rel of rels) {
                    if (rel.type === "FIGHT" && rel.fromFight) {
                        const src =
                            fightMap.get(rel.fromFight.id) ?? rel.fromFight;
                        if (!src) continue;
                        // Only traverse within the same bracket (group) to avoid cross-bracket pollution
                        if (
                            bracketGroupId !== null &&
                            src.group?.id !== bracketGroupId
                        )
                            continue;
                        if (!visited.has(src.id)) {
                            visited.add(src.id);
                            next.push(src);
                        }
                    }
                }
            }
            layer = next;
        }
        stages.reverse();
        return stages;
    }

    const winnersStages = $derived(collectBracket(config.winnersFinalFight));
    const losersStages = $derived(collectBracket(config.losersFinalFight));
    const grandFinal = fightMap.get(config.grandFinalFight);

    function stageName(count: number, isWinners: boolean): string {
        switch (count) {
            case 1:
                return isWinners ? "Finale (W)" : "Finale (L)";
            case 2:
                return isWinners ? "Halbfinale (W)" : "Halbfinale (L)";
            case 4:
                return isWinners ? "Viertelfinale (W)" : "Viertelfinale (L)";
            case 8:
                return isWinners ? "Achtelfinale (W)" : "Achtelfinale (L)";
            default:
                return `Runde (${count}) ${isWinners ? "W" : "L"}`;
        }
    }

    let connector: any;
    const unsubscribe = fightConnector.subscribe((v) => (connector = v));
    onDestroy(() => {
        connector.clearAllConnections();
        unsubscribe();
    });

    function buildConnections() {
        if (!connector) return;
        connector.clearAllConnections();
        // Track offsets per source fight and team to stagger multiple outgoing lines for visual clarity
        const fightTeamOffsetMap = new Map<string, number>();
        const step = 8; // px separation between parallel lines
        for (const rel of event.relations) {
            if (rel.type !== "FIGHT" || !rel.fromFight) continue;
            const fromId = rel.fromFight.id;
            const fromEl = document.getElementById(
                `fight-${fromId}`,
            ) as HTMLElement | null;
            const toEl = document.getElementById(
                `fight-${rel.fight}-team-${rel.team.toLowerCase()}`,
            ) as HTMLElement | null;
            if (!fromEl || !toEl) continue;
            // Use team-signed offsets so BLUE goes left (negative), RED goes right (positive)
            const key = `${fromId}:${rel.team}`;
            const index = fightTeamOffsetMap.get(key) ?? 0;
            const sign = rel.team === "BLUE" ? -1 : 1;
            const offset = sign * (index + 1) * step;
            const color = rel.fromPlace === 0 ? "#60a5fa" : "#f87171";
            connector.addConnection(fromEl, toEl, color, offset);
            fightTeamOffsetMap.set(key, index + 1);
        }
    }

    onMount(async () => {
        await tick();
        buildConnections();
    });
</script>

{#if !grandFinal}
    <p class="text-gray-400 italic">
        Konfiguration unvollständig (Grand Final fehlt).
    </p>
{:else}
    {#key winnersStages.length + ":" + losersStages.length}
        <!-- Build a grid where rows: winners (stages), losers (stages), with losers offset by one stage/column -->
        {@const totalColumns =
            Math.max(winnersStages.length, losersStages.length + 1) + 1}
        <div
            class="grid gap-x-16 gap-y-6 items-start"
            style={`grid-template-columns: repeat(${totalColumns}, max-content);`}
        >
            <!-- Winners heading spans all columns -->
            <h2 class="font-bold text-center">Winners Bracket</h2>

            <!-- Winners stages in row 2 -->
            {#each winnersStages as stage, i}
                <div style={`grid-row: 2; grid-column: ${i + 1};`}>
                    <EventCard title={stageName(stage.length, true)}>
                        {#each stage as fight}
                            <EventFightChip
                                {event}
                                {fight}
                                group={fight.group ?? defaultGroup}
                            />
                        {/each}
                    </EventCard>
                </div>
            {/each}

            <!-- Place Grand Final at the far right, aligned with winners row -->
            <div
                style={`grid-row: 2; grid-column: ${totalColumns};`}
                class="self-center"
            >
                <EventCard title="Grand Final">
                    {#if grandFinal}
                        <EventFightChip
                            {event}
                            fight={grandFinal}
                            group={grandFinal.group ?? defaultGroup}
                        />
                    {/if}
                </EventCard>
            </div>

            <!-- Losers heading spans all columns -->
            <h2
                class="font-bold text-center"
                style="grid-row: 3; grid-column: 1 / {totalColumns};"
            >
                Losers Bracket
            </h2>

            <!-- Losers stages in row 4, offset by one column to the right -->
            {#each losersStages as stage, j}
                <div style={`grid-row: 4; grid-column: ${j + 2};`} class="mt-2">
                    <EventCard title={stageName(stage.length, false)}>
                        {#each stage as fight}
                            <EventFightChip
                                {event}
                                {fight}
                                group={fight.group ?? defaultGroup}
                            />
                        {/each}
                    </EventCard>
                </div>
            {/each}
        </div>
    {/key}
{/if}
