import { world } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";
import * as utils from "../utils";
import * as gld from "../gld";
import * as inventory_utils from "../inventory_utils";
import { showApp as main_menu, checkDepletedBattery } from "./main_menu"; 
import * as biome_check from "../biome_check";
import * as wallet from "../wallet";
import { showApp as finances } from "./bank";
import * as Vector3 from "../vector3";


let ticksPassed = 0;

// let rainbow = undefined;

const realismSettingsData = gld.getAppData("realism_settings");

const SETTINGS = {
    sunLight: true,
    wind: true,
    birds: true,
    rainbow: true,
    fog: true
}

const playerData = {};

function isDayTime()
{
    const currentTime = world.getTimeOfDay();
    return (currentTime < 12800 || currentTime > 23200);
}

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

    let RealismSettingsApp = new ActionFormData()
        .title(realismSettingsData.name)
        .body(gld.getScreenTitle(player) + "Use this app to enable/disable visual effects.");

    for (let effect of gld.RealismData.effects) {
        const isUnlocked = playerData[player.id][effect.effect];
        if (isUnlocked) {
            const isEnabled = SETTINGS[effect.effect];
            RealismSettingsApp.button(
                `＀§l${effect.color}${effect.name} §8(${isEnabled ? "§2Enabled": "§4Disabled"}§8)\n` + 
                `${isEnabled ? "§4Click to disable": "§2Click to enable"}`, 
                effect.icon
            );
        } else {
            const canAfford = wallet.canAfford(player, effect.cost);
            const color = canAfford ? "§2": "§4";
            RealismSettingsApp.button(
                `＀§l${effect.color}${effect.name}\n` + 
                `${color}Purchase for (§6${effect.cost}${gld.coinSymbol}${color})`,
                effect.icon
            );
        }
    }

    RealismSettingsApp.button("＀§lBack", "textures/goe/spa/ui/back");

    RealismSettingsApp.show(player).then(result => {
        inventory_utils.replacePhoneIfUIClosed(player, result);
        if (result.canceled) return;

        if (result.selection < gld.RealismData.effects.length) {
            const selectedEffect = gld.RealismData.effects[result.selection];
            const isUnlocked = playerData[player.id][selectedEffect.effect];
            if (isUnlocked) {
                const value = SETTINGS[selectedEffect.effect];
                world.setDynamicProperty(selectedEffect.property, !value);
                SETTINGS[selectedEffect.effect] = !value;
                player.playSound("goe_spa:submit");
            } else {
                const canAfford = wallet.canAfford(player, selectedEffect.cost);
                if (!canAfford) {
                    player.playSound("goe_spa:button_click");
                    showCantAffordForm(player, selectedEffect.name, selectedEffect.cost);
                    return;
                }

                player.playSound("goe_spa:upgrade");
                wallet.charge(player, selectedEffect.cost);
                
                player.setDynamicProperty(selectedEffect.property, true);
                playerData[player.id][selectedEffect.effect] = true;

                // world.setDynamicProperty(selectedEffect.property, true);
                // SETTINGS[selectedEffect.effect] = true;
            }

            showApp(player);
            return;
        }

        player.playSound("goe_spa:button_click");
        main_menu(player);
    });
}

export async function onTick() {    
    // Update settings
    SETTINGS.sunLight = world.getDynamicProperty("goe_spa_sun_light") !== undefined ? world.getDynamicProperty("goe_spa_sun_light") : false;
    SETTINGS.birds = world.getDynamicProperty("goe_spa_birds") !== undefined ? world.getDynamicProperty("goe_spa_birds") : false;
    SETTINGS.fog =  world.getDynamicProperty("goe_spa_fog") !== undefined ? world.getDynamicProperty("goe_spa_fog") : false;
    SETTINGS.rainbow = world.getDynamicProperty("goe_spa_rainbow") !== undefined ? world.getDynamicProperty("goe_spa_rainbow") : false;
    SETTINGS.wind =  world.getDynamicProperty("goe_spa_wind") !== undefined ? world.getDynamicProperty("goe_spa_wind") : false;

    ++ticksPassed;

    removeSunLights();

    for (const player of world.getAllPlayers()) {   
        if (!player.dimension.id.endsWith("overworld"))
        {
            if (player.getDynamicProperty("goe_spa_fog") === true)
                removeFog(player);
            continue;
        }

        // Update player data
        playerData[player.id] = {
            sunLight: player.getDynamicProperty("goe_spa_sun_light") !== undefined ? player.getDynamicProperty("goe_spa_sun_light") : true,
            birds: player.getDynamicProperty("goe_spa_birds") !== undefined ? player.getDynamicProperty("goe_spa_birds") : false,
            fog: player.getDynamicProperty("goe_spa_fog") !== undefined ? player.getDynamicProperty("goe_spa_fog") : false,
            rainbow: player.getDynamicProperty("goe_spa_rainbow") !== undefined ? player.getDynamicProperty("goe_spa_rainbow") : false,
            wind: player.getDynamicProperty("goe_spa_wind") !== undefined ? player.getDynamicProperty("goe_spa_wind") : false,
        };

        if (isDayTime() && (ticksPassed % gld.RealismData.birds.spawnInterval === 0))
            spawnBird(player);

        updateWeatherEffects(player);
    }
}


async function spawnBird(player) {
    if (!SETTINGS.birds || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    // Get random bird particle
    const randomIndex = Math.floor(Math.random() * gld.RealismData.birds.particles.length);
    let randomParticle = gld.RealismData.birds.particles[randomIndex];

    try {
        player.dimension.spawnParticle(randomParticle, player.location);
    } catch (error) {}
}

async function updateWeatherEffects(player) {
    const biomeType = biome_check.getBiome(player);
    const weatherType = biome_check.getWeather(player);

    updateSunLightEffect(player, weatherType, biomeType);

    removeFog(player);

    if (weatherType === 0) { // Clear
        spawnNormalWeatherEffects(player, biomeType);

        updateRainbow(player);
    } else if (weatherType === 1) { // Rain
        addFog(player, biomeType);
        spawnBadWeatherEffects(player, biomeType);
    }

}

function addFog(player, biomeType) {
    if (!SETTINGS.fog || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    if (biome_check.isInBiome(player, "frozen")) {
        utils.runPlayerCommand(player, "/fog @s push goe_spa:snow_fog goe_spa:snow_fog");
    } else if (biomeType === "desert")
        utils.runPlayerCommand(player, "/fog @s push goe_spa:desert_fog goe_spa:desert_fog");
    else if (biomeType === "mesa")
        utils.runPlayerCommand(player, "/fog @s push goe_spa:mesa_fog goe_spa:mesa_fog");
    else
        utils.runPlayerCommand(player, "/fog @s push goe_spa:rain_fog goe_spa:rain_fog");
}

function removeFog(player) {
    utils.runPlayerCommand(player, "/fog @s pop goe_spa:snow_fog");
    utils.runPlayerCommand(player, "/fog @s pop goe_spa:rain_fog");
    utils.runPlayerCommand(player, "/fog @s pop goe_spa:desert_fog");
    utils.runPlayerCommand(player, "/fog @s pop goe_spa:mesa_fog");
}

function spawnNormalWeatherEffects(player, biomeType) {
    if (ticksPassed % gld.RealismData.wind.normalInterval === 0)
        spawnLightWind(player);

    if (ticksPassed % gld.RealismData.sand.normalInterval === 0)
        spawnSandDust(player, biomeType);

    if (ticksPassed % gld.RealismData.mist.normalInterval === 0)
        spawnMist(player, biomeType);

    if (ticksPassed % gld.RealismData.sand.normalInterval === 0)
        spawnSnowDust(player);
}

function spawnLightWind(player) {
    if (!SETTINGS.wind || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    try {
        player.dimension.spawnParticle("goe_spa:regular_wind", player.location);
    } catch (error) {}
}

function spawnBadWeatherEffects(player, biomeType) {
    if (ticksPassed % gld.RealismData.wind.rainInterval === 0) {
        spawnStrongWind(player);

        if (biome_check.isInBiome(player, "frozen")) {
            spawnSnowParticles(player);
            spawnSnowDust(player);
        } else if (biomeType === "desert" || biomeType === "mesa") {
            spawnSandstrom(player, biomeType);
        } else {
            spawnRainParticles(player);
        }
    }

    if (ticksPassed % gld.RealismData.sand.rainInterval === 0)
        spawnSandDust(player, biomeType);
}

function spawnStrongWind(player) {
    if (!SETTINGS.wind || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;
    
    try {
        player.dimension.spawnParticle("goe_spa:regular_wind", player.location);
        player.dimension.spawnParticle("goe_spa:storm_wind", player.location);
    } catch (error) {}

}

function spawnSnowParticles(player) {
    if (!SETTINGS.fog || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    try {
        player.dimension.spawnParticle("goe_spa:snow_particles", player.location);
    } catch (error) {}
}

function spawnRainParticles(player) {
    if (!SETTINGS.fog || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    try {
        player.dimension.spawnParticle("goe_spa:rain_particles", player.location);
    } catch (error) {}
}

function updateRainbow(player) {
    if (!SETTINGS.rainbow || player.id !== utils.player0.id || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    if (!isDayTime())
        return;

    // if (rainbow === undefined) {
    //     rainbow = utils.overworld.spawnEntity(`goe_spa:rainbow`, player.location);
    //     if (!rainbow || !rainbow.isValid()) {
    //         rainbow = undefined;
    //         return;
    //     }
    // }

    // utils.runEntityCommand(rainbow, `tp @s ${player.location.x} 140 ${player.location.z} 0 0`);

    // utils.runPlayer0Command("particle goe_spa:rainbow ~-240 50 ~");

    const targetPosition = player.location;
    targetPosition.y = 64;
    let rainbow = utils.overworld.spawnEntity(`goe_spa:rainbow`, targetPosition);
    if (!rainbow || !rainbow.isValid()) {
        return;
    }

    // Smoother following
    let velocity = player.getVelocity();
    rainbow.applyImpulse(velocity);
}

function spawnMist(player, biomeType) {
    if (!SETTINGS.fog || biome_check.isUnderground(player) || biome_check.isInWater(player) || biomeType === "desert" || biomeType === "mesa")
        return;

    // if (world.getTimeOfDay() > 12000 || world.getTimeOfDay() < 1000)
    try {
        player.dimension.spawnParticle("goe_spa:mist", player.location);
    } catch (error) {}
}

function spawnSandDust(player, biomeType) {
    if (!SETTINGS.wind || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    try {
        if (biomeType === "desert")
            player.dimension.spawnParticle("goe_spa:sand_dust", player.location);
        else if (biomeType === "mesa")
            player.dimension.spawnParticle("goe_spa:red_sand_dust", player.location);    
    } catch (error) {}
}

function spawnSnowDust(player) {
    if (!SETTINGS.fog || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    if (!biome_check.isInBiome(player, "frozen"))
        return;

    try {
        player.dimension.spawnParticle("goe_spa:snow_dust", player.location);    
    } catch (error) {}
}

function spawnSandstrom(player, biomeType) {
    if (!SETTINGS.wind || biome_check.isUnderground(player) || biome_check.isInWater(player))
        return;

    if (biomeType === "desert")
        player.dimension.spawnParticle("goe_spa:sand_particles", player.location);
    else if (biomeType === "mesa")
        player.dimension.spawnParticle("goe_spa:red_sand_particles", player.location);
}


function updateSunLightEffect(player, currentWeather, currentBiome) {
    // Check if sun light effect is enabled and not blocked by weather conditions
    if (!SETTINGS.sunLight || (currentWeather === 1 && currentBiome !== "desert" && currentBiome !== "mesa")) {
        return;
    }

    const currentTime = world.getTimeOfDay();
    let isDay = isDayTime();

    let lightType = isDay ? 'sun' : 'moon';
    let lightOffset = gld.getLightOffset(currentTime, isDay);

    let playerFaceLocation = Vector3.PlayerFace.add(player.location);
    let lightLocation = playerFaceLocation.add(lightOffset);
    let lightDirection = Vector3.unit(lightOffset);

        // Check if sun is blocked by some block
    try {
        const blockInView = utils.overworld.getBlockFromRay(playerFaceLocation, lightDirection, {
            includeLiquidBlocks: true,
            includePassableBlocks: false,
            maxDistance: 200
        });

        // If view is blocked, prevent sunlight effect
        if (blockInView && blockInView.block && blockInView.block.isValid() && !blockInView.block.isAir)
            return;

        // Spawn sun light entity with appropriate opacity
        player.dimension.spawnEntity(`goe_spa:sun_light<goe_spa:${lightType}>`, lightLocation);

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

}

async function removeSunLights() {
    utils.overworld.getEntities({ type: 'goe_spa:sun_light' }).forEach(entity => {
        if (!entity.isValid())
            return;
        entity.remove();
    });

    utils.overworld.getEntities({ type: 'goe_spa:rainbow' }).forEach(entity => {
        if (!entity.isValid())
            return;
        entity.remove();
    });
}

function showCantAffordForm(player, effect, cost) {
    const CantAffordForm = new ActionFormData();
    CantAffordForm.title(realismSettingsData.name);
    CantAffordForm.body(
        gld.getScreenTitle(player) +
        `\nNot enough Smartcoins (§6${gld.coinSymbol}§r).\n\n` + 
        `    §e${effect}\n\n` +
        `§cCost:      ${cost} ${gld.coinSymbol}§r\n` + 
        `§4Missing:   ${cost - wallet.getBalance(player)} ${gld.coinSymbol}§r\n\n`
    );
    CantAffordForm.button("§eGet Smartcoins", gld.getAppData("bank").icon);
    CantAffordForm.button("Back", "textures/goe/spa/ui/back");

    CantAffordForm.show(player).then((response) => {
        player.playSound("goe_spa:button_click");
        if (response.selection == 0) {
            finances(player);
            return;
        }

        showApp(player);
    });
}