import { system } from "@minecraft/server";
import { ActionFormData, ModalFormData } from "@minecraft/server-ui";
import * as utils from "../utils";
import * as inventory_utils from "../inventory_utils";
import * as gld from "../gld";
import { showApp as main_menu, checkDepletedBattery } from "./main_menu"; 
import { stopMusic } from "./play_music";

let guessTheNumberData = gld.getAppData("guess_the_number");

const data = {};

const stats = {
    wins: "goe_spa_gtn_wins",
    fails: "goe_spa_gtn_fails",
    fastest: "goe_spa_gtn_fastests",
}

const MAX_ATEMPTS = 10;

export async function showApp(player){
    if (await checkDepletedBattery(player))
        return;

    // Create layout
    const GuessTheNumberForm = new ActionFormData();
    GuessTheNumberForm.title(guessTheNumberData.name);
    GuessTheNumberForm.body(
        gld.getScreenTitle(player) + 

        `Welcome to Guess the Number\n(Mini game)\n\n` + 
        `The game chooses a secret number between 1 and 100, and you get 10 attempts to guess it.\n` + 
        `Every time you guess, you'll get a hint if the secret number is higher or lower than the number you guessed.\n` + 
        `Your goal is to find the secret number with as few guesses as possible. Let's see how fast you can do it!\n\n` + 

        `§lStats:§r\n` +
        `§aWins§f: ${getNumber(player, stats.wins)}\n` + 
        `§cFails§f: ${getNumber(player, stats.fails)}\n` + 
        `§bFastest Win§f: ${getNumber(player, stats.fastest)} guesses\n\n`
    );

    GuessTheNumberForm.button("§2Play", "textures/goe/spa/ui/confirm");
    GuessTheNumberForm.button("§4Reset stats", "textures/goe/spa/ui/delete");
    GuessTheNumberForm.button("Back", "textures/goe/spa/ui/back");
    
    // Display app
    GuessTheNumberForm.show(player).then(result => {
        inventory_utils.replacePhoneIfUIClosed(player, result);
        if (result.canceled)
            return;

        player.playSound("goe_spa:button_click");

        if (result.selection == 0) {
            // Create data
            data[player.id] = { 
                targetNumber: Math.round(Math.random() * 99) + 1,
                guesses: [],
            };

            stopMusic(player, false);
            player.playSound("goe_spa:mini_game_music");

            // Start game
            showGuessingPage(player);
        } else if (result.selection == 1) {
            // Reset stats
            showConfirmForm(player).then(result => {
                inventory_utils.replacePhoneIfUIClosed(player, result);
                if (result.canceled)
                    return;

                if (result.selection === 0) {
                    player.playSound("goe_spa:delete");
                    resetStats(player);
                } else {
                    player.playSound("goe_spa:cancel");
                }
                
                showApp(player);
            }).catch(error => {
                utils.debug(error.message);
            });
        } else {
            main_menu(player);
        }
    
    }).catch(error => {
        utils.debug(error.message);
    });
}

async function showGuessingPage(player) {
    if (data[player.id].guesses.length >= MAX_ATEMPTS) {
        setStat(player, stats.fails, getNumber(player, stats.fails) + 1);
        showLostPage(player);
        return;
    }

    // Create layout
    const GuessingPageForm = new ModalFormData();
    GuessingPageForm.title(guessTheNumberData.name);

    let bodyText = `§l§bGuess the secret number§r\n\n`;

    data[player.id].guesses.forEach((previousGuess, index) => {
        bodyText += `Guess #${index + 1}: ${previousGuess}\n`;
    });

    bodyText += "\n";

    GuessingPageForm.textField(bodyText + "Type your number (1-100):", "Enter number here");

    GuessingPageForm.submitButton("Guess");

    // Display app
    GuessingPageForm.show(player).then(formData => {
        inventory_utils.replacePhoneIfUIClosed(player, formData);
        if (formData.canceled || !formData.formValues) {
            // Stop music
            utils.runPlayerCommand(player, "stopsound @s goe_spa:mini_game_music");
            return;
        }

        player.playSound("goe_spa:button_click");
        
        const guessValue = parseInt(formData.formValues[0]);
        if (!guessValue || guessValue < 1 || guessValue > 100) {
            player.playSound("goe_spa:cancel");
            showGuessingPage(player);
            return;
        }

        const targetNumber = data[player.id].targetNumber;

        if (guessValue === targetNumber) {
            setStat(player, stats.wins, getNumber(player, stats.wins) + 1);

            const fastestGuess = getNumber(player, stats.fastest);
            const numberOfGuesses = data[player.id].guesses.length + 1;
            if (fastestGuess === 0 || numberOfGuesses < fastestGuess)
                setStat(player, stats.fastest, numberOfGuesses);

            showWinPage(player);
        } else if (guessValue < targetNumber) {
            player.playSound("goe_spa:cancel");
            data[player.id].guesses.push(`${guessValue} (§btoo low§f)`);
            showGuessingPage(player);
        } else {
            player.playSound("goe_spa:cancel");
            data[player.id].guesses.push(`${guessValue} (§btoo high§f)`);
            showGuessingPage(player);
        }

    }).catch(error => {
        utils.debug(error.message);
    });
}

async function showWinPage(player) {
    // Stop music
    utils.runPlayerCommand(player, "stopsound @s goe_spa:mini_game_music");

    // Firework particles
    player.playSound("goe_spa:win");
    player.playSound("goe_spa:victory");
    playerFireworks(player, {x: 1.5, y: 0.5, z: 2});
    system.runTimeout(() => playerFireworks(player, {x: -1.5, y: 0, z: 2}), 5);
    system.runTimeout(() => playerFireworks(player, {x: 1.5, y: 0, z: 2}), 10);
    system.runTimeout(() => playerFireworks(player, {x: -1.5, y: 0.5, z: 2}), 15);

    // Create layout
    const WinPageForm = new ActionFormData();
    WinPageForm.title(guessTheNumberData.name);
    WinPageForm.body(
        gld.getScreenTitle(player) + 

        `Congratulations, you did it!\n` + 
        `You found the secret number in ${data[player.id].guesses.length + 1} guesses. ` + 
        `Very nice.\n\n` +

        `§lStats:§r\n` +
        `§aWins§f: ${getNumber(player, stats.wins)}\n` + 
        `§cFails§f: ${getNumber(player, stats.fails)}\n` + 
        `§bFastest Win§f: ${getNumber(player, stats.fastest)} guesses\n\n`
    );

    WinPageForm.button("§2Try Again", "textures/goe/spa/ui/confirm");
    WinPageForm.button("Back", "textures/goe/spa/ui/back");
    
    // Display app
    WinPageForm.show(player).then(result => {
        inventory_utils.replacePhoneIfUIClosed(player, result);
        if (result.canceled)
            return;

        player.playSound("goe_spa:button_click");

        if (result.selection == 0) {
            // Create data
            data[player.id] = { 
                targetNumber: Math.round(Math.random() * 99) + 1,
                guesses: [],
            };

            // Start game again
            player.playSound("goe_spa:mini_game_music");
            showGuessingPage(player);
        } else {
            main_menu(player);
        }
    
    }).catch(error => {
        utils.debug(error.message);
    });
}

async function showLostPage(player) {
    // Stop music
    utils.runPlayerCommand(player, "stopsound @s goe_spa:mini_game_music");

    player.playSound("goe_spa:lose");

    // Create layout
    const LostPageForm = new ActionFormData();
    LostPageForm.title(guessTheNumberData.name);
    LostPageForm.body(
        gld.getScreenTitle(player) + 

        `No more guesses.\n` + 
        `You were so close.\n\n` + 

        `§lStats:§r\n` +
        `§aWins§f: ${getNumber(player, stats.wins)}\n` + 
        `§cFails§f: ${getNumber(player, stats.fails)}\n` + 
        `§bFastest Win§f: ${getNumber(player, stats.fastest)} guesses\n\n`
    );

    LostPageForm.button("§2Try Again", "textures/goe/spa/ui/confirm");
    LostPageForm.button("Back", "textures/goe/spa/ui/back");
    
    // Display app
    LostPageForm.show(player).then(result => {
        inventory_utils.replacePhoneIfUIClosed(player, result);
        if (result.canceled)
            return;

        player.playSound("goe_spa:button_click");

        if (result.selection == 0) {
            // Create data
            data[player.id] = { 
                targetNumber: Math.round(Math.random() * 99) + 1,
                guesses: [],
            };

            // Start game again
            player.playSound("goe_spa:mini_game_music");
            showGuessingPage(player);
        } else {
            main_menu(player);
        }
    
    }).catch(error => {
        utils.debug(error.message);
    });
}


async function showConfirmForm(player) {
    // Set layout
    const ConfirmForm = new ActionFormData();
    ConfirmForm.title(guessTheNumberData.name);
    ConfirmForm.body(
        `All game stats will be deleted and set back to zero.\n\n` + 
        `Are you sure?`
    );

    ConfirmForm.button("§aConfirm", "textures/goe/spa/ui/confirm");
    ConfirmForm.button("§4Cancel", "textures/goe/spa/ui/cancel");

    // Return promise
    return ConfirmForm.show(player);
}

function resetStats(player) {
    setStat(player, stats.wins, 0);
    setStat(player, stats.fails, 0);
    setStat(player, stats.fastest, 0);
}

function getNumber(player, stat) {
    const result = player.getDynamicProperty(stat);
    if (!result)
        return 0;

    return result;
}   

function setStat(player, stat, value) {
    player.setDynamicProperty(stat, value);
}

async function playerFireworks(player, offset) {
    utils.runPlayerCommand(player, `particle goe_spa:fireworks ^${offset.x} ^${offset.y} ^${offset.z}`);
    utils.runPlayerCommand(player, "playsound firework.blast");
    utils.runPlayerCommand(player, "playsound firework.large_blast");
    utils.runPlayerCommand(player, "playsound firework.twinkle");
}