<!--
  -   This file is a part of the SteamWar software.
  -
  -   Copyright (C) 2023 SteamWar.de-Serverteam
  -
  -   This program is free software: you can redistribute it and/or modify
  -   it under the terms of the GNU Affero General Public License as published by
  -   the Free Software Foundation, either version 3 of the License, or
  -   (at your option) any later version.
  -
  -   This program is distributed in the hope that it will be useful,
  -   but WITHOUT ANY WARRANTY; without even the implied warranty of
  -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  -   GNU Affero General Public License for more details.
  -
  -   You should have received a copy of the GNU Affero General Public License
  -   along with this program.  If not, see <https://www.gnu.org/licenses/>.
  -->

<script lang="ts">
    import type {EventFight, ExtendedEvent} from "@type/event.ts";
    import {
        Button,
        Checkbox, Input, Label,
        Modal,
        SpeedDial,
        SpeedDialButton,
        Toolbar,
        ToolbarButton,
        ToolbarGroup,
        Tooltip
    } from "flowbite-svelte";
    import {
        ArrowsRepeatSolid, CalendarWeekOutline,
        PlusSolid, ProfileCardOutline, TrashBinOutline, UsersGroupOutline,
    } from "flowbite-svelte-icons";
    import FightCard from "./FightCard.svelte";
    import CreateFightModal from "./modals/CreateFightModal.svelte";
    import {groups, players} from "@stores/stores.ts";
    import TypeAheadSearch from "../../components/TypeAheadSearch.svelte";
    import {fightRepo, type UpdateFight} from "@repo/fight.ts";
    import dayjs from "dayjs";
    import duration from "dayjs/plugin/duration";

    dayjs.extend(duration);

    export let data: ExtendedEvent;

    let createOpen = false;
    let fights = data.fights;
    let selectedFights: Set<EventFight> = new Set();

    $: groupsMap = new Set(fights.map(fight => fight.group));
    $: groupedFights = Array.from(groupsMap).map(group => {
        return {
            group: group,
            fights: fights.filter(fight => fight.group === group)
        };
    });

    function cycleSelect() {
        if (selectedFights.size === fights.length) {
            selectedFights = new Set();
        } else if (selectedFights.size === 0) {
            selectedFights = new Set(fights.filter(fight => fight.start > Date.now()));

            if (selectedFights.size === 0) {
                selectedFights = new Set(fights);
            }
        } else {
            selectedFights = new Set(fights);
        }
    }

    function cycleGroup(groupFights: EventFight[]) {
        if (groupFights.every(gf => selectedFights.has(gf))) {
            groupFights.forEach(fight => selectedFights.delete(fight));
        } else {
            groupFights.forEach(fight => selectedFights.add(fight));
        }
        selectedFights = selectedFights;
    }

    let deleteOpen = false;

    async function deleteFights() {
        for (const fight of selectedFights) {
            await $fightRepo.deleteFight(fight.id);
        }
        fights = await $fightRepo.listFights(data.event.id);
        selectedFights = new Set();
        deleteOpen = false;
    }

    let spectatePortOpen = false;
    $: selectPlayers = $players.map(player => {
        return {
            name: player.name,
            value: player.id.toString()
        };
    }).sort((a, b) => a.name.localeCompare(b.name));
    let spectatePort = "";

    async function updateSpectatePort() {
        for (const fight of selectedFights) {
            let f: UpdateFight = {
                blueTeam: null,
                group: null,
                spectatePort: Number.parseInt(spectatePort),
                map: null,
                redTeam: null,
                spielmodus: null,
                start: null
            };
            await $fightRepo.updateFight(fight.id, f);
        }
        fights = await $fightRepo.listFights(data.event.id);
        selectedFights = new Set();
        spectatePort = "";
        spectatePortOpen = false;
    }

    let groupChangeOpen = false;
    let group = "";
    let groupSearch = "";

    $: selectableGroups = [{
        name: "None",
        value: ""
    }, {
        value: groupSearch,
        name: `Create: '${groupSearch}'`
    }, ...$groups.map(group => {
        return {
            name: group,
            value: group
        };
    }).sort((a, b) => a.name.localeCompare(b.name))];

    async function updateGroup() {
        for (const fight of selectedFights) {
            let f: UpdateFight = {
                blueTeam: null,
                group: group,
                spectatePort: null,
                map: null,
                redTeam: null,
                spielmodus: null,
                start: null
            };
            await $fightRepo.updateFight(fight.id, f);
        }
        fights = await $fightRepo.listFights(data.event.id);
        selectedFights = new Set();
        group = "";
        groupSearch = "";
        groupChangeOpen = false;
    }

    $: minTime = dayjs(Math.min(...fights.map(fight => fight.start))).utc(true);
    let changeTimeOpen = false;
    let changedTime = fights.length != 0 ? dayjs(Math.min(...fights.map(fight => fight.start)))?.utc(true)?.toISOString()?.slice(0, -1) : undefined;

    $: deltaTime = dayjs.duration(dayjs(changedTime).utc(true).diff(minTime));

    async function updateStartTime() {
        for (const fight of selectedFights) {
            let f: UpdateFight = {
                blueTeam: null,
                group: null,
                spectatePort: null,
                map: null,
                redTeam: null,
                spielmodus: null,
                start: dayjs(fight.start).add(deltaTime.asMilliseconds(), "millisecond")
            };
            await $fightRepo.updateFight(fight.id, f);
        }
        fights = await $fightRepo.listFights(data.event.id);
        changedTime = minTime.toISOString().slice(0, -1);
        selectedFights = new Set();
        changeTimeOpen = false;
    }
</script>

<svelte:head>
    <title>{data.event.name} - Fights</title>
</svelte:head>

<div class="pb-28">
    <Toolbar class="mx-4 mt-2 w-fit">
        <ToolbarGroup>
            <Checkbox class="ml-2" checked={selectedFights.size === fights.length} on:click={cycleSelect}/>
            <Tooltip>Select Upcoming</Tooltip>
        </ToolbarGroup>
        <ToolbarGroup>
            <ToolbarButton on:click={() => selectedFights.size > 0 ? changeTimeOpen = true : changeTimeOpen = false}>
                <CalendarWeekOutline/>
            </ToolbarButton>
            <Tooltip>Reschedule Fights</Tooltip>
            <ToolbarButton on:click={() => selectedFights.size > 0 ? spectatePortOpen = true : spectatePortOpen = false}
                           disabled={changedTime === undefined}>
                <ProfileCardOutline/>
            </ToolbarButton>
            <Tooltip>Change Spectate Port</Tooltip>
            <ToolbarButton on:click={() => selectedFights.size > 0 ? groupChangeOpen = true : groupChangeOpen = false}>
                <UsersGroupOutline/>
            </ToolbarButton>
            <Tooltip>Change Group</Tooltip>
        </ToolbarGroup>
        <ToolbarGroup>
            <ToolbarButton color="red"
                           on:click={() => selectedFights.size > 0 ? deleteOpen = true : deleteOpen = false}>
                <TrashBinOutline/>
            </ToolbarButton>
            <Tooltip>Delete</Tooltip>
        </ToolbarGroup>
    </Toolbar>
    {#each groupedFights as group}
        <div class="flex mt-4">
            <Checkbox class="ml-2 text-center" checked={group.fights.every(gf => selectedFights.has(gf))}
                      on:click={() => cycleGroup(group.fights)}/>
            <h1 class="ml-4 text-2xl">{group.group ?? "Ungrouped"}</h1>
        </div>
        {#each group.fights.sort((a, b) => a.start - b.start) as fight, i (fight.id)}
            <FightCard {fight} {i} {data} selected={selectedFights.has(fight)}
                       on:select={() => {
                    if (selectedFights.has(fight)) {
                        selectedFights.delete(fight);
                    } else {
                        selectedFights.add(fight);
                    }
                    selectedFights = selectedFights;
                }}
                       on:update={async () => fights = await $fightRepo.listFights(data.event.id)}
            />
        {/each}
    {/each}
</div>

<CreateFightModal {data} bind:open={createOpen}
                  on:create={async () => data.fights = await $fightRepo.listFights(data.event.id)}></CreateFightModal>

<Modal bind:open={deleteOpen} title="Delete {selectedFights.size} Fights" autoclose size="sm">
    <p>Are you sure you want to delete {selectedFights.size} fights?</p>
    <svelte:fragment slot="footer">
        <Button color="red" class="ml-auto" on:click={deleteFights}>Delete</Button>
        <Button on:click={() => deleteOpen = false} color="alternative">Cancel</Button>
    </svelte:fragment>
</Modal>

<Modal bind:open={spectatePortOpen} title="Change Kampfleiter" size="sm">
    <div class="m-2">
        <Label for="fight-kampf">Kampfleiter</Label>
        <TypeAheadSearch items={selectPlayers} bind:selected={spectatePort}></TypeAheadSearch>
    </div>
    <svelte:fragment slot="footer">
        <Button class="ml-auto" on:click={updateSpectatePort}>Change</Button>
        <Button on:click={() => spectatePortOpen = false} color="alternative">Cancel</Button>
    </svelte:fragment>
</Modal>

<Modal bind:open={groupChangeOpen} title="Change Group" size="sm">
    <div class="m-2">
        <Label for="fight-kampf">Group</Label>
        <TypeAheadSearch items={selectableGroups} bind:selected={group} bind:searchValue={groupSearch}
                         all></TypeAheadSearch>
    </div>
    <svelte:fragment slot="footer">
        <Button class="ml-auto" on:click={updateGroup}>Change</Button>
        <Button on:click={() => groupChangeOpen = false} color="alternative">Cancel</Button>
    </svelte:fragment>
</Modal>

<Modal bind:open={changeTimeOpen} title="Change Start Time" size="sm">
    <div class="m-2">
        <Label for="fight-start">New Start Time:</Label>
        <Input id="fight-start" bind:value={changedTime} let:props>
            <input type="datetime-local" {...props} bind:value={changedTime}/>
        </Input>
    </div>
    <p>{deltaTime.asMilliseconds() < 0 ? '' : '+'}{("0" + deltaTime.hours()).slice(-2)}
        :{("0" + deltaTime.minutes()).slice(-2)}</p>
    <svelte:fragment slot="footer">
        <Button class="ml-auto" on:click={updateStartTime}>Update</Button>
        <Button on:click={() => changeTimeOpen = false} color="alternative">Cancel</Button>
    </svelte:fragment>
</Modal>

<SpeedDial>
    <SpeedDialButton name="Add" on:click={() => createOpen = true}>
        <PlusSolid/>
    </SpeedDialButton>
    <SpeedDialButton name="Generate" href="#/event/{data.event.id}/generate">
        <ArrowsRepeatSolid/>
    </SpeedDialButton>
</SpeedDial>
