<script lang="ts">
    import Wall from "$lib/Wall.svelte";
    import type { Player } from "$lib/Player";
    import { GameState } from "$lib/GameState";
    import {
        isMultipleChoiceQuestion,
        isSimpleQuestion,
        isImageQuestion,
        isAudioQuestion,
        isAudioMultipleChoiceQuestion,
        isImageMultipleChoiceQuestion,
        type FullGame
    } from "$lib/games/games";
    import ws from "$lib/websocket.svelte";
    import { page } from "$app/state";
    import { MessageType } from "$lib/MessageType";
    import GameStateSvelte from "$lib/GameState.svelte.js";
    import Scoreboard from "$lib/Scoreboard.svelte";
    import SimpleQuestionComponent from "$lib/SimpleQuestionComponent.svelte";
    import PlusMinusButton from "$lib/PlusMinusButton.svelte";
    import type { VisitedQuestions } from "$lib/Types.js";
    import MultipleChoiceQuestionComponent from "$lib/MultipleChoiceQuestionComponent.svelte";
    import ImageQuestionComponent from "$lib/ImageQuestionComponent.svelte";
    import AudioQuestionComponent from "$lib/AudioQuestionComponent.svelte";
    import AudioMultipleChoiceQuestionComponent from "$lib/AudioMultipleChoiceQuestionComponent.svelte";
    import ImageMultipleChoiceQuestionComponent from "$lib/ImageMultipleChoiceQuestionComponent.svelte";

    interface SaveData {
        players: Player[];
        currentPlayer: number;
        currentWall: number;
        visitedQuestions: VisitedQuestions;
    }

    let startDisabled = $state(true);

    function handleDisplayConnected() {
        if (!startDisabled) {
            gameManager?.sendStart();
            gameManager?.sendCurrentState();
            startDisabled = false;
        }
    }

    function handleDisplayDisconnected() {
        startDisabled = true;
    }

    $effect(() => {
        console.log("Display connected:", GameStateSvelte.displayConnected);
        if (GameStateSvelte.displayConnected) {
            handleDisplayConnected();
        } else {
            handleDisplayDisconnected();
        }
    });

    class GameManager {
        public state: GameState = $state(GameState.INIT);
        public game: FullGame;
        public players: Player[] = $state([
            {
                name: "Player 1",
                points: 0
            },
            {
                name: "Player 2",
                points: 0
            },
            {
                name: "Player 3",
                points: 0
            }
        ]);

        public currentPlayer = $state(0);
        public currentWall = $state(0);
        public visitedQuestions: VisitedQuestions = $state([]);
        public currentCategory = $state(0);
        public currentQuestion = $state(0);

        public answerIsShowing = $state(false);
        public questionIsShowing = $state(false);
        public isBuzzed = $state(false);

        constructor(game: FullGame) {
            this.game = game;
        }

        save(): void {
            const saveData = {
                players: this.players,
                currentPlayer: this.currentPlayer,
                currentWall: this.currentWall,
                visitedQuestions: this.visitedQuestions
            };
            localStorage.setItem(`saveGame-${this.game.name}`, JSON.stringify(saveData));
        }

        load(): void {
            const saveDataString = localStorage.getItem(`saveGame-${this.game.name}`);
            if (saveDataString === null) return;
            try {
                const saveData: SaveData = JSON.parse(saveDataString);
                this.players = saveData.players;
                this.currentPlayer = saveData.currentPlayer;
                this.currentWall = saveData.currentWall;
                this.visitedQuestions = saveData.visitedQuestions;
                console.log(saveData);
            } catch (e) {
                //
            }
        }

        startGame(): void {
            this.currentPlayer = Math.floor(Math.random() * this.players.length);
            this.state = GameState.CHOOSING_QUESTION;
            this.sendStart();
            this.sendCurrentState();
        }

        sendStart(): void {
            ws.sendMessage({
                type: MessageType.START
            });
        }

        sendPlayers(): void {
            ws.sendMessage({
                type: MessageType.PLAYERS,
                players: this.players,
                current: this.currentPlayerToName()
            });
        }

        sendWall(): void {
            ws.sendMessage({
                type: MessageType.GOTO,
                route: `/${page.params.game}/${this.currentWall}`
            });
            this.sendVisited();
        }

        sendVisited(): void {
            ws.sendMessage({
                type: MessageType.VISITED_QUESTIONS,
                visitedQuestions: this.visitedQuestions
            });
        }

        sendCurrentState(): void {
            this.sendPlayers();
            this.sendWall();
        }

        sendCurrentQuestion(): void {
            ws.sendMessage({
                type: MessageType.GOTO,
                route: `/${page.params.game}/${this.currentWall}/${this.currentCategory}/${this.currentQuestion}`
            });
        }

        sendEnd(): void {
            ws.sendMessage({
                type: MessageType.GOTO,
                route: `/${page.params.game}/${this.currentWall}/end`
            });
        }

        tileClicked(categoryIndex: number, questionIndex: number) {
            console.log("Cat", categoryIndex, "Que", questionIndex);
            console.log(gameManager.wall.categories[categoryIndex]?.questions[questionIndex]);

            this.currentCategory = categoryIndex;
            this.currentQuestion = questionIndex;
            this.answerIsShowing = false;

            this.sendCurrentQuestion();

            this.state = GameState.SHOW_QUESTION;
        }

        addPlayer() {
            this.players.push({
                name: "Player " + (this.players.length + 1),
                points: 0
            });
        }

        removePlayer(index: number) {
            this.players.splice(index, 1);
        }

        showAnswer() {
            this.answerIsShowing = true;
            this.questionIsShowing = true;
            ws.sendMessage({
                type: MessageType.SHOW_ANSWER
            });
        }

        hideAnswer() {
            this.answerIsShowing = false;
            ws.sendMessage({
                type: MessageType.HIDE_ANSWER
            });
        }

        buzzerPressed() {
            this.isBuzzed = true;
            ws.sendMessage({
                type: MessageType.BUZZER_PRESSED
            });
        }

        buzzerReleased() {
            this.isBuzzed = false;
            ws.sendMessage({
                type: MessageType.BUZZER_RELEASED
            });
        }

        showQuestion() {
            this.questionIsShowing = true;
            ws.sendMessage({
                type: MessageType.SHOW_QUESTION
            });
        }

        hideQuestion() {
            this.questionIsShowing = false;
            this.answerIsShowing = false;
            ws.sendMessage({
                type: MessageType.HIDE_QUESTION
            });
        }

        plus(player: Player) {
            if (!this.answerIsShowing) return;
            if (player.name === this.currentPlayerToName()) {
                player.points += this.question.points * 2;
            } else {
                player.points += this.question.points;
            }
            this.sendPlayers();
        }

        minus(player: Player) {
            if (player.name === this.currentPlayerToName()) {
                player.points -= this.question.points * 2;
            } else {
                player.points -= this.question.points;
            }
            this.sendPlayers();
        }

        goBack(): void {
            this.sendWall();
            this.state = GameState.CHOOSING_QUESTION;
            this.setupGoingBack();
        }

        setupGoingBack(): void {
            this.answerIsShowing = false;
            this.questionIsShowing = false;
            this.isBuzzed = false;
        }

        finishQuestion(): void {
            if (this.visitedQuestions[this.currentCategory] == undefined) {
                this.visitedQuestions[this.currentCategory] = [this.currentQuestion];
            } else if (
                !this.visitedQuestions[this.currentCategory].includes(this.currentQuestion)
            ) {
                this.visitedQuestions[this.currentCategory].push(this.currentQuestion);
            }
            this.setupGoingBack();
            this.nextPlayer();
            if (this.wallIsDone()) {
                this.goToNextWall();
            } else {
                this.sendWall();
                this.state = GameState.CHOOSING_QUESTION;
            }
            this.save();
        }

        wallIsDone(): boolean {
            let visitedNum = 0;
            for (const questions of this.visitedQuestions) {
                if (questions != undefined) {
                    visitedNum += questions.length;
                }
            }
            let totalNum = 0;
            for (const category of this.wall.categories) {
                totalNum += category.questions.length;
            }
            console.log(`${visitedNum} >= ${totalNum}`);
            return visitedNum >= totalNum;
        }

        goToNextWall(): void {
            if (this.currentWall + 1 >= this.game.walls.length) {
                this.goToEndScreen();
            } else {
                this.currentWall += 1;
                this.visitedQuestions = [];
                this.sendWall();
                this.state = GameState.CHOOSING_QUESTION;
            }
        }

        goToEndScreen(): void {
            this.sendEnd();
            this.state = GameState.END;
        }

        nextPlayer(): void {
            this.currentPlayer = (this.currentPlayer + 1) % this.players.length;
            this.sendPlayers();
        }

        currentPlayerToName(): string {
            return this.players[this.currentPlayer].name;
        }

        get wall() {
            return this.game.walls[this.currentWall];
        }

        get category() {
            return this.wall.categories[this.currentCategory];
        }

        get question() {
            return this.category.questions[this.currentQuestion];
        }
    }

    let { data } = $props();

    let gameManager = new GameManager(data);
</script>

<div class="flex h-full flex-col">
    <h1 class="ms-4 text-7xl font-bold">{gameManager.game.name}</h1>
    {#if gameManager.state === GameState.INIT}
        <div class="p-4">
            <div class="flex items-center">
                <h2 class="grow pb-4 text-5xl">Spieler</h2>
                <button class="btn me-4" onclick={() => gameManager.load()}>Load SaveGame</button>
                <button
                    class="btn"
                    disabled={!startDisabled}
                    onclick={() => gameManager.startGame()}>Start</button
                >
            </div>
            <div class="flex flex-col space-y-2 pb-4">
                {#each gameManager.players as player, i}
                    <div class="flex items-center">
                        <input class="inputField grow" type="text" bind:value={player.name} />
                        <button class="btn" onclick={() => gameManager.removePlayer(i)}
                            >Löschen</button
                        >
                    </div>
                {/each}
            </div>
            <button class="btn" onclick={() => gameManager.addPlayer()}>Spieler hinzufügen</button>
        </div>
    {:else}
        <div class="flex grow">
            <Scoreboard
                players={gameManager.players}
                currentPlayer={gameManager.currentPlayerToName()}
                editable={true}
                onReload={() => gameManager.sendPlayers()}
            />
            {#if gameManager.state === GameState.SHOW_QUESTION}
                <div class="flex grow flex-col">
                    <div class="m-4 flex justify-between text-4xl">
                        <div>{gameManager.category.name}</div>
                        <div>
                            {gameManager.question.points} Punkte
                        </div>
                    </div>
                    <div class="flex grow ps-4 pe-4">
                        {#if gameManager.question === undefined}
                            <p>Question is undefined</p>
                        {:else if isSimpleQuestion(gameManager.question)}
                            <SimpleQuestionComponent
                                question={gameManager.question}
                                showAnswer={true}
                                showQuestion={true}
                            />
                        {:else if isMultipleChoiceQuestion(gameManager.question)}
                            <MultipleChoiceQuestionComponent
                                question={gameManager.question}
                                showAnswer={true}
                                showQuestion={true}
                            />
                        {:else if isImageQuestion(gameManager.question)}
                            <ImageQuestionComponent
                                question={gameManager.question}
                                showAnswer={true}
                                showQuestion={true}
                                isBuzzed={false}
                            />
                        {:else if isImageMultipleChoiceQuestion(gameManager.question)}
                            <ImageMultipleChoiceQuestionComponent
                                question={gameManager.question}
                                showAnswer={true}
                                showQuestion={true}
                                isBuzzed={false}
                            />
                        {:else if isAudioQuestion(gameManager.question)}
                            <AudioQuestionComponent
                                question={gameManager.question}
                                showAnswer={true}
                                showPlayer={true}
                                showQuestion={true}
                            />
                        {:else if isAudioMultipleChoiceQuestion(gameManager.question)}
                            <AudioMultipleChoiceQuestionComponent
                                question={gameManager.question}
                                showAnswer={true}
                                showPlayer={true}
                                showQuestion={true}
                            />
                        {:else}
                            <p>Type of question unknown</p>
                        {/if}
                    </div>
                    <div class="m-4 flex flex-wrap items-center gap-4">
                        <button class="btn" onclick={() => gameManager.goBack()}>Zurück</button>
                        {#if gameManager.questionIsShowing}
                            <button class="btn" onclick={() => gameManager.hideQuestion()}
                                >Frage verstecken</button
                            >
                        {:else}
                            <button class="btn" onclick={() => gameManager.showQuestion()}
                                >Frage aufdecken</button
                            >
                        {/if}
                        {#if gameManager.answerIsShowing}
                            <button class="btn" onclick={() => gameManager.hideAnswer()}
                                >Antwort verstecken</button
                            >
                        {:else}
                            <button class="btn" onclick={() => gameManager.showAnswer()}
                                >Antwort aufdecken</button
                            >
                        {/if}
                        {#if gameManager.isBuzzed}
                            <button class="btn" onclick={() => gameManager.buzzerReleased()}
                                >Entbuzzern</button
                            >
                        {:else}
                            <button class="btn" onclick={() => gameManager.buzzerPressed()}
                                >Buzzern</button
                            >
                        {/if}
                        {#each gameManager.players as player}
                            <PlusMinusButton
                                label={player.name}
                                plus={() => gameManager.plus(player)}
                                minus={() => gameManager.minus(player)}
                                showPlus={gameManager.answerIsShowing}
                            />
                        {/each}
                        <div class="grow"></div>
                        {#if gameManager.answerIsShowing}
                            <button class="btn" onclick={() => gameManager.finishQuestion()}
                                >Abschließen</button
                            >
                        {/if}
                    </div>
                </div>
            {:else if gameManager.state === GameState.END}
                <div class="flex grow items-center justify-center text-7xl"><div>ENDE</div></div>
            {:else}
                <div class="grow ps-4 pe-4">
                    <Wall
                        wall={gameManager.game.walls[gameManager.currentWall]}
                        onclick={(cat, que) => gameManager.tileClicked(cat, que)}
                        visited={gameManager.visitedQuestions}
                    />
                </div>
            {/if}
        </div>
    {/if}
</div>
