import { ActionFormData, ModalFormData, MessageFormData } from "@minecraft/server-ui";
import { world } from "@minecraft/server";
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 * as Vector3 from "../vector3";

const stats = {
    distance_today: "goe_spa_distance_today",
    distance_total: "goe_spa_distance_total",
    blocks_digged: "goe_spa_blocks_digged",
    highest_block: "goe_spa_highest_block",
    lowest_block: "goe_spa_lowest_block",
}

const playersData = {};

let fitnessData = gld.getAppData("fitness");

export async function showApp(player){
    if (await checkDepletedBattery(player))
        return;
    // Create layout
    let distanceToday = getNumber(player, stats.distance_today).toFixed(0);
    let distanceTotal = getNumber(player, stats.distance_total).toFixed(0);
    let FitnessApp = new ActionFormData();
    FitnessApp.title(fitnessData.name);
    FitnessApp.body(
        gld.getScreenTitle(player) + 
        `§3Blocks traveled today: §e${distanceToday} ${getCorrectBlocksString(distanceToday)}\n\n` + 
        `§3Total blocks traveled: §d${distanceTotal} ${getCorrectBlocksString(distanceTotal)}\n\n` + 
        `§3Total blocks mined: §n${getNumber(player, stats.blocks_digged)} ${getCorrectBlocksString(getNumber(player, stats.blocks_digged))}\n\n` + 
        `§3Highest peak reached: §a${getNumber(player, stats.highest_block)}\n\n` + 
        `§3Lowest cave reached: §b${getNumber(player, stats.lowest_block)}\n\n`
    );

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

        player.playSound("goe_spa:button_click");
        if (result.selection == 0) {
            showConfirmForm(player).then(async result => {
                if (result.canceled)
                    return;

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

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

async function showConfirmForm(player) {
    // Set layout
    const ConfirmForm = new ActionFormData();
    ConfirmForm.title(fitnessData.name);
    ConfirmForm.body(
        `All fitness 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);
}

export async function onTick() {
    for (const player of world.getAllPlayers()) {
        calculateBlocksTraveled(player);
        calculateHighestBlock(player);
        calculateLowestBlock(player);
    }
}

function calculateBlocksTraveled(player) {
    const playerData = getPlayerData(player);
    const currentPosition = player.location;
    const distance = Vector3.distance(currentPosition, playerData.lastTickPosition);
    playerData.lastTickPosition = currentPosition;

    // Is new day started
    if (world.getTimeOfDay() === 0) {
        setStat(player, stats.distance_today, 0);
    } else {
        let value = getNumber(player, stats.distance_today);
        value += distance;
        setStat(player, stats.distance_today, value);
    }

    let value = getNumber(player, stats.distance_total);
    value += distance;
    setStat(player, stats.distance_total, value);
}

function calculateHighestBlock(player) {
    if (player.hasTag("goe_spa_satellite_mode"))
        return;
    
    const currentY = player.location.y;
    const highestY = player.getDynamicProperty(stats.highest_block);

    if (highestY !== undefined && highestY >= currentY)
        return;

    player.setDynamicProperty(stats.highest_block, currentY.toFixed(0));
}

function calculateLowestBlock(player) {
    const currentY = player.location.y;
    const lowestY = player.getDynamicProperty(stats.lowest_block);

    if (lowestY !== undefined && lowestY <= currentY)
        return;

    player.setDynamicProperty(stats.lowest_block, currentY.toFixed(0));
}

function getPlayerData(player) {
    if (playersData[player.id] === undefined) {
        playersData[player.id] = { player: player, lastTickPosition: player.location };
    }

    return playersData[player.id];
}

export async function onPlayerBreakBlock(event) {
    const player = event.player;
    let count = getNumber(player, stats.blocks_digged);
    setStat(player, stats.blocks_digged, count + 1);
}

function getNumber(player, name) {
    const rawValue = getRawStat(player, name);
    if (!rawValue)
        return 0;

    return parseFloat(rawValue);
}

function getRawStat(player, name) {
    return player.getDynamicProperty(name);
}

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

function resetStats(player) {
    setStat(player, stats.distance_today, 0);
    setStat(player, stats.distance_total, 0);
    setStat(player, stats.blocks_digged, 0);
    setStat(player, stats.highest_block, undefined);
    setStat(player, stats.lowest_block, undefined);

    calculateBlocksTraveled(player);
    calculateHighestBlock(player);
    calculateLowestBlock(player);
}

function getCorrectBlocksString(numberOfBlocks){
    if (numberOfBlocks == 1)
        return "block";
    return "blocks";
}