import { world, system } from "@minecraft/server";
import * as languages from "./languages";

var lastTick = Date.now();
var tps = 20;
var timeArray = [];
system.runInterval(() => {
    if (timeArray.length === 20) timeArray.shift();
    timeArray.push(Date.now() - lastTick);
    tps = Math.round(1000 / (timeArray.reduce((a, b) => a + b) / timeArray.length));
    lastTick = Date.now();
})

function getElapsedTime(joinTime) {
    const ticks = system.currentTick - joinTime;
    const secs = Math.floor((ticks / 20) % 60).toString().padStart(2, "0");
    const mins = Math.floor((ticks / 1200) % 60).toString().padStart(2, "0");
    const hours = Math.floor(ticks / 72000).toString().padStart(2, "0");
    return hours + ":" + mins + ":" + secs;
}

function getDirection(angle, lang) {
    if(angle < 0) angle = 360 - Math.abs(angle);
    if((225 < angle) && (angle <= 315)) {
        return lang.directionList.east;
    } else if((45 <= angle) && (angle < 135)) {
        return lang.directionList.west;
    } else if ((135 < angle) && (angle <= 225)) {
        return lang.directionList.north;
    } else {
        return lang.directionList.south;
    }
}

function getChunkLoc(location) {
    const chunkX = Math.floor(location.x/16);
    const chunkZ = Math.floor(location.z/16);
    const locInChunkX = Math.floor(location.x - 16 * chunkX);
    const locInChunkZ = Math.floor(location.z - 16 * chunkZ);
    return `${chunkX}, ${chunkZ} (${locInChunkX}, ${locInChunkZ})`;
}

world.afterEvents.playerSpawn.subscribe((e) => {
    if(e.initialSpawn == false) return;
    const joinTime = system.currentTick;
    const player = e.player;

    // language setup
    if(world.getDynamicProperty("dslang") == undefined) {
        world.setDynamicProperty("dslang", "{}")
    }
    var dslang = JSON.parse(world.getDynamicProperty("dslang"));
    if(!Object.keys(dslang).includes(player.nameTag)) {
        dslang[player.nameTag] = "english";
        world.setDynamicProperty("dslang", JSON.stringify(dslang));
    }
    var lang = languages[dslang[player.nameTag]];

    // language command
    world.afterEvents.chatSend.subscribe(event => {
        if(event.sender != player || !event.message.startsWith("!ds")) return;
        const cmd = event.message.slice(4);
        if(cmd.startsWith("help")) {
            player.sendMessage(`§2${lang.cmdChatList.help}`);
        } else if(cmd.startsWith("lang")) {
            if(cmd.trim() == "lang") {
                player.sendMessage(`§2${lang.cmdChatList.lang_list}\n§a${Object.keys(languages)}`)
            } else {
                const newLang = cmd.slice(5).trim();
                if(!Object.keys(languages).includes(newLang)) {
                    player.sendMessage(`§c${lang.cmdChatList.no_lang}`);
                } else {
                    dslang = JSON.parse(world.getDynamicProperty("dslang"));
                    dslang[player.nameTag] = newLang;
                    world.setDynamicProperty("dslang", JSON.stringify(dslang));
                    lang = languages[dslang[player.nameTag]];
                    player.sendMessage(`§2${lang.cmdChatList.lang_set} §a${newLang}`);
                }
            }
        } else {
            player.sendMessage(`§c${lang.cmdChatList.no_cmd}`);
        }
    });
    
    // data store variables
    var biome;
    var lightLevel;
    var difficulty;
    var inVillage;
    var isUnderground;

    // data check variables
    var elTime;
    var chunkLoc;
    var entityCount;
    var dimension;
    var direction;
    var weather;
    var dayCount;
    var moonPhase;
    var preTps;
    var preLightLevel;
    var preDifficulty;
    var preBiome;
    var preInVillage;
    var preIsUnderground;

    // data event recievers
    world.afterEvents.dataDrivenEntityTrigger.subscribe((e) => {
        if(e.entity != player || !e.eventId.startsWith("star")) return;
        const id = e.eventId.slice(5, 9);
        const value = e.eventId.slice(10);
        
        if(id == "0001") {
            lightLevel = value;
        } else if(id == "0010") {
            difficulty = lang.difficultyList[value];
        } else if(id == "0011") {
            inVillage = lang.booleans[value];
        } else if(id == "0100") {
            isUnderground = lang.booleans[value];
        } else if(id == "0101") {
            biome = value;
        }
    });
    
    // data transfer
    var i2 = 1;
    var i3 = 1;
    var i4 = 1;
    system.runInterval(() => {
        // tick 1
        if(!player.isValid()) return;
       player.runCommandAsync(`title @s title &&&!${lang.labels.aoa} ${Math.round(player.getRotation().x*(-1))}º`);

        // tick 2
        system.runTimeout(() => {
            if(direction != getDirection(player.getRotation().y, lang)) {
                direction = getDirection(player.getRotation().y, lang);
                player.runCommandAsync(`title @s title &&!&${lang.labels.direction} ${direction}`);
            } else if(chunkLoc != getChunkLoc(player.location)) {
                chunkLoc = getChunkLoc(player.location);
                player.runCommandAsync(`title @s title !!!!${lang.labels.chunkLoc} ${chunkLoc}`);
            } else if(entityCount != player.dimension.getEntities({location: player.location, maxDistance: 96}).length) {
                entityCount = player.dimension.getEntities({location: player.location, maxDistance: 96}).length;
                player.runCommandAsync(`title @s title !!&!${lang.labels.entityCount} ${entityCount}`);
            } else {
                switch(i2) {
                    case 1:
                        i2 = 2;
                        player.runCommandAsync(`title @s title !!&!${lang.labels.entityCount} ${entityCount}`);
                        break;
                    case 2:
                        i2 = 3;
                        player.runCommandAsync(`title @s title &&!&${lang.labels.direction} ${direction}`);
                        break;
                    case 3:
                        i2 = 1;
                        player.runCommandAsync(`title @s title !!!!${lang.labels.chunkLoc} ${chunkLoc}`);
                }
            }
        }, 1);

        // tick 3
        system.runTimeout(() => {
            if(preTps != tps) {
                preTps = tps;
                player.runCommandAsync(`title @s title &&!!${lang.labels.tps} ${tps}`);
            } else if(preLightLevel != lightLevel) {
                preLightLevel = lightLevel;
                player.runCommandAsync(`title @s title &!&&${lang.labels.lightLevel} ${lightLevel}`);
            } else {
                switch(i3) {
                    case 1:
                        i3 = 2;
                        player.runCommandAsync(`title @s title &&!!${lang.labels.tps} ${tps}`);
                        break;
                    case 2:
                        i3 = 1;
                        player.runCommandAsync(`title @s title &!&&${lang.labels.lightLevel} ${lightLevel}`);
                }
            }
        }, 2);

        // tick 4
        system.runTimeout(() => {
            if(elTime != getElapsedTime(joinTime)) {
                elTime = getElapsedTime(joinTime);
                player.runCommandAsync(`title @s title !!!&${lang.labels.elTime} ${elTime}`);
            } else if(dimension != player.dimension.id) {
                dimension = player.dimension.id;
                player.runCommandAsync(`title @s title &!&!${lang.labels.dimension} ${lang.dimensionList[dimension]}`);
            } else if(weather != player.dimension.getWeather()) {
                weather = player.dimension.getWeather();
                player.runCommandAsync(`title @s title &!!&${lang.labels.weather} ${lang.weatherList[weather]}`);
            } else if(dayCount != world.getDay()) {
                dayCount = world.getDay();
                player.runCommandAsync(`title @s title &!!!${lang.labels.dayCount} ${dayCount}`);
            } else if(moonPhase != world.getMoonPhase()) {
                moonPhase = world.getMoonPhase();
                player.runCommandAsync(`title @s title !&&&${lang.labels.moonPhase} ${lang.moonPhaseList[moonPhase]}`);
            } else if(preBiome != biome) {
                preBiome = biome;
                player.runCommandAsync(`title @s title !&&!${lang.labels.biome} ${lang.biomeList[biome]}`);
            } else if(preInVillage != inVillage) {
                preInVillage = inVillage;
                player.runCommandAsync(`title @s title !&!&${lang.labels.inVillage} ${inVillage}`);
            } else if(preIsUnderground != isUnderground) {
                preIsUnderground = isUnderground;
                player.runCommandAsync(`title @s title !&!!${lang.labels.isUnderground} ${isUnderground}`);
            } else if(preDifficulty != difficulty) {
                preDifficulty = difficulty;
                player.runCommandAsync(`title @s title !!&&${lang.labels.difficulty} ${difficulty}`);
            } else {
                switch(i4) {
                    case 1:
                        i4 = 2;
                        player.runCommandAsync(`title @s title &!&!${lang.labels.dimension} ${lang.dimensionList[dimension]}`);
                        break;
                    case 2:
                        i4 = 3;
                        player.runCommandAsync(`title @s title &!!&${lang.labels.weather} ${lang.weatherList[weather]}`);
                        break;
                    case 3:
                        i4 = 4;
                        player.runCommandAsync(`title @s title &!!!${lang.labels.dayCount} ${dayCount}`);
                        break;
                    case 4:
                        i4 = 5;
                        player.runCommandAsync(`title @s title !&&&${lang.labels.moonPhase} ${lang.moonPhaseList[moonPhase]}`);
                        break;
                    case 5:
                        i4 = 6;
                        player.runCommandAsync(`title @s title !&&!${lang.labels.biome} ${lang.biomeList[biome]}`);
                        break;
                    case 6:
                        i4 = 7;
                        player.runCommandAsync(`title @s title !&!&${lang.labels.inVillage} ${inVillage}`);
                        break;
                    case 7:
                        i4 = 8;
                        player.runCommandAsync(`title @s title !&!!${lang.labels.isUnderground} ${isUnderground}`);
                        break;
                    case 8:
                        i4 = 9;
                        player.runCommandAsync(`title @s title !!&&${lang.labels.difficulty} ${difficulty}`);
                        break;
                    case 9:
                        i4 = 1;
                        player.runCommandAsync(`title @s title !!!&${lang.labels.elTime} ${elTime}`);
                }
            }
        }, 3);
    }, 4);
});
