<script lang="ts">
    import DragAcceptor from "@components/admin/pages/generate/DragAcceptor.svelte";
    import TeamChip from "@components/admin/pages/generate/TeamChip.svelte";
    import { eventRepo } from "@components/repo/event";
    import { fightRepo } from "@components/repo/fight";
    import { gamemodes, maps } from "@components/stores/stores";
    import type { ExtendedEvent } from "@components/types/event";
    import type { Team } from "@components/types/team";
    import { Button } from "@components/ui/button";
    import { Card } from "@components/ui/card";
    import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte";
    import { Dialog } from "@components/ui/dialog";
    import { Input } from "@components/ui/input";
    import { Label } from "@components/ui/label";
    import { Select, SelectContent, SelectItem, SelectTrigger } from "@components/ui/select";
    import { Slider } from "@components/ui/slider";
    import { fromAbsolute, fromDate, parseDateTime, parseDuration } from "@internationalized/date";
    import dayjs from "dayjs";
    import { Plus } from "lucide-svelte";
    import { replace } from "svelte-spa-router";
    let {
        data,
    }: {
        data: ExtendedEvent;
    } = $props();

    let teams = $derived(new Map<number, Team>(data.teams.map((team) => [team.id, team])));

    let groups: number[][] = $state([]);
    let teamsNotInGroup = $derived(data.teams.filter((team) => !groups.flat().includes(team.id)));

    function dragToNewGroup(event: DragEvent) {
        event.preventDefault();
        let teamId = parseInt(event.dataTransfer!.getData("team"));
        groups = [...groups.map((value) => value.filter((value1) => value1 != teamId)), [teamId]].filter((value) => value.length > 0);
    }

    function teamDragStart(ev: DragEvent, team: Team) {
        ev.dataTransfer!.setData("team", team.id.toString());
    }

    let resetDragOver = $state(false);

    function resetDragOverEvent(ev: DragEvent) {
        resetDragOver = true;
        ev.preventDefault();
    }

    function dropReset(ev: DragEvent) {
        ev.preventDefault();
        let teamId = parseInt(ev.dataTransfer!.getData("team"));
        groups = groups.map((group) => group.filter((team) => team !== teamId)).filter((group) => group.length > 0);
        resetDragOver = false;
    }

    function dropGroup(ev: DragEvent, groupIndex: number) {
        ev.preventDefault();
        let teamId = parseInt(ev.dataTransfer!.getData("team"));
        groups = groups.map((group, i) => (i === groupIndex ? [...group.filter((value) => value != teamId), teamId] : group.filter((value) => value != teamId))).filter((group) => group.length > 0);
    }

    let startTime = $state(fromAbsolute(data.event.start, "Europe/Berlin"));
    let gamemode = $state("");
    let map = $state("");

    let selectableGamemodes = $derived(
        $gamemodes
            .map((gamemode) => {
                return {
                    name: gamemode,
                    value: gamemode,
                };
            })
            .sort((a, b) => a.name.localeCompare(b.name))
    );

    let mapsStore = $derived(maps(gamemode));
    let selectableMaps = $derived(
        $mapsStore
            .map((map) => {
                return {
                    name: map,
                    value: map,
                };
            })
            .sort((a, b) => a.name.localeCompare(b.name))
    );

    let roundTime = $state(30);
    let startDelay = $state(30);

    let showAutoGrouping = $state(false);
    let groupCount = $state(Math.floor(data.teams.length / 2));

    function createGroups() {
        let teams = data.teams.map((team) => team.id).sort(() => Math.random() - 0.5);
        groups = [];
        for (let i = 0; i < groupCount; i++) {
            groups.push([]);
        }
        while (teams.length > 0) {
            groups[teams.length % groupCount].push(teams.pop() as number);
        }
        showAutoGrouping = false;
        groups = groups.filter((group) => group.length > 0);
    }

    function generateGroups(groups: number[][]): number[][][][] {
        const groupFights: number[][][][] = [];
        groups.forEach((group) => {
            let round = group.length + (group.length % 2) - 1;
            let groupFight = [];
            for (let i = 0; i < round; i++) {
                let availableTeams = [...group];
                if (group.length % 2 === 1) {
                    availableTeams = availableTeams.filter((team, index) => index !== i);
                }
                let roundFights = [];
                while (availableTeams.length > 0) {
                    let team1 = availableTeams.pop() as number;
                    let team2 = availableTeams.at(i % availableTeams.length) as number;
                    availableTeams = availableTeams.filter((team) => team !== team2);
                    let fight = [team1, team2];
                    fight.sort(() => Math.random() - 0.5);
                    roundFights.push(fight);
                }
                groupFight.push(roundFights);
            }
            groupFights.push(groupFight);
        });
        return groupFights;
    }

    let groupsFights = $derived(generateGroups(groups));

    let generateDisabled = $derived(groupsFights.length > 0 && groupsFights.every((value) => value.every((value1) => value1.length > 0)) && gamemode !== "" && map !== "");

    async function generateFights() {
        groupsFights.forEach((group, i) => {
            $eventRepo
                .createGroup(data.event.id, {
                    name: "Gruppe " + (i + 1),
                    type: "GROUP_STAGE",
                })
                .then((v) => {
                    group.forEach((round, j) => {
                        round.forEach(async (fight, k) => {
                            const blueTeam = teams.get(fight[0])!;
                            const redTeam = teams.get(fight[1])!;

                            let karte = map;

                            if (karte === "%random%") {
                                karte = selectableMaps[Math.floor(Math.random() * selectableMaps.length)].value;
                            }

                            await $fightRepo.createFight(data.event.id, {
                                blueTeam: blueTeam.id,
                                redTeam: redTeam.id,
                                group: v.id,
                                map: karte,
                                spectatePort: null,
                                spielmodus: gamemode,
                                start: dayjs(
                                    startTime
                                        .copy()
                                        .add({
                                            minutes: roundTime * j,
                                        })
                                        .add({
                                            seconds: startDelay * (k + i * round.length),
                                        })
                                        .toDate()
                                ),
                            });
                        });
                    });
                });
        });

        await replace("#/event/" + data.event.id);
    }
</script>

<div class="flex justify-between">
    <Card
        id="reseter"
        class="flex w-fit p-2 border border-gray-700 rounded h-20 pt-6 relative {resetDragOver ? 'border-white' : ''}"
        ondragover={resetDragOverEvent}
        ondragleave={() => (resetDragOver = false)}
        ondrop={dropReset}
        role="group"
    >
        {#each teamsNotInGroup as team (team.id)}
            <TeamChip {team} ondragstart={(ev) => teamDragStart(ev, team)} />
        {/each}
    </Card>

    <div class="flex items-center mr-4">
        <Button onclick={() => (showAutoGrouping = true)}>Automatische Gruppen</Button>
    </div>
</div>

<div class="flex mt-4 gap-4 border-b border-gray-700 pb-4">
    {#each groups as group, i (i)}
        <DragAcceptor ondrop={(ev) => dropGroup(ev, i)}>
            <h1>Gruppe {i + 1} ({group.length})</h1>
            {#each group as teamId (teamId)}
                <TeamChip team={teams.get(teamId)!} ondragstart={(ev) => teamDragStart(ev, teams.get(teamId)!)} />
            {/each}
        </DragAcceptor>
    {/each}
    <DragAcceptor ondrop={dragToNewGroup}>
        <h1>Neue Gruppe</h1>
    </DragAcceptor>
</div>

<div class="border-b mt-4 border-gray-700 pb-4">
    <Label for="event-end">Startzeit</Label>
    <DateTimePicker bind:value={startTime} />
    <div class="mt-2">
        <Label for="event-roundtime">Rundenzeit: {roundTime}m</Label>
        <Slider id="event-roundtime" type="single" bind:value={roundTime} step={1} min={5} max={60} />
    </div>
    <div class="mt-2">
        <Label for="event-member">Startverzögerung: {startDelay}</Label>
        <Slider id="event-member" type="single" bind:value={startDelay} step={1} min={0} max={30} />
    </div>
    <div class="mt-2">
        <Label for="fight-gamemode">Spielmodus</Label>
        <Select type="single" bind:value={gamemode}>
            <SelectTrigger id="fight-gamemode">{gamemode}</SelectTrigger>
            <SelectContent>
                {#each selectableGamemodes as gamemodeOption}
                    <SelectItem value={gamemodeOption.value}>{gamemodeOption.name}</SelectItem>
                {/each}
            </SelectContent>
        </Select>
    </div>
    <div class="mt-2">
        <Label for="fight-maps">Map</Label>
        <Select type="single" bind:value={map}>
            <SelectTrigger id="fight-maps">{map}</SelectTrigger>
            <SelectContent>
                <SelectItem value="%random%">Zufällige Map</SelectItem>
                {#each selectableMaps as mapOption}
                    <SelectItem value={mapOption.value}>{mapOption.name}</SelectItem>
                {/each}
            </SelectContent>
        </Select>
    </div>
</div>

<div class="text-center mx-2">
    {#each groupsFights as fightsGroup, i}
        <div>
            <h1 class="text-4xl">Gruppe: {i + 1}</h1>
            {#each fightsGroup as fightsRound, j}
                <div class="border-b border-gray-700">
                    <h1 class="text-2xl">Runde: {j + 1}</h1>
                    {#each fightsRound as fightTeams, k}
                        <div class="text-left p-4">
                            <span class="p-2 border border-gray-700 rounded"
                                >{new Intl.DateTimeFormat("de-DE", {
                                    day: "2-digit",
                                    month: "2-digit",
                                    year: "2-digit",

                                    hour: "2-digit",
                                    minute: "2-digit",
                                    second: "2-digit",
                                }).format(
                                    startTime
                                        .copy()
                                        .add({
                                            minutes: roundTime * j,
                                            seconds: startDelay * (k + i * fightsRound.length),
                                        })
                                        .toDate()
                                )}</span
                            >
                            {teams.get(fightTeams[0])!.name} vs. {teams.get(fightTeams[1])!.name}
                        </div>
                    {/each}
                </div>
            {/each}
        </div>
    {/each}
</div>

<Button class="!p-4 fixed bottom-4 right-4" disabled={!generateDisabled} onclick={generateFights}>
    <Plus />
</Button>

<style lang="scss">
    :global(#reseter::before) {
        content: "Reset";
        position: absolute;
        top: 0;
        color: white;
    }

    :global(#reseter) {
        min-width: 14rem;
    }
</style>
