import {
    world,
    system,
    Entity,
    Player,
    MinecraftBlockTypes,
    EquipmentSlot,
    ItemStack,
    ItemTypes,
    BlockAreaSize,
    Vector,
    ItemLockMode
} from '@minecraft/server';
import {
    ActionFormData,
    ModalFormData,
    MessageFormData
} from '@minecraft/server-ui';
import { TPparticles } from './effect.js'

console

Object.defineProperty(Player.prototype, "scores", {
    get() {
        const {
            scoreboard
        } = this;
        const {
            scoreboard: worldSB
        } = world;
        return new Proxy({}, {
            get(_, objective) {
                const obj = worldSB.getObjective(objective) ?? worldSB.addObjective(objective, objective);
                try {
                    return worldSB.getScore(obj, scoreboard);
                } catch {
                    return 0;
                };
            },
            set(_, objective, value) {
                const obj = worldSB.getObjective(objective) ?? worldSB.addObjective(objective, objective);
                try {
                    return worldSB.setScore(obj, scoreboard, value);
                } catch {
                    this.runCommandAsync(`scoreboard players set @s "${objective}" ${value}`);
                };
            }
        });
    }
});

const overworld = world.getDimension("minecraft:overworld");
const nether = world.getDimension("minecraft:nether");
const theEnd = world.getDimension("minecraft:the_end");

const colors = {
    codes: "§e|§0|§b|§d|§6|§2|§a|§1|§c|§n",
    values: ["§l§eYELLOW",
        "§l§0BLACK",
        "§l§bLIGHT BLUE",
        "§l§dPINK",
        "§l§6ORANGE",
        "§l§2GREEN",
        "§l§aLIME",
        "§l§1BLUE",
        "§c§lRED",
        "§l§nBROWN"]
};

const create = new ModalFormData()
.title("Create your own waypoint")
.textField("Name of your waypoint", "Example")
.dropdown("Color name", colors.values, 0)
.toggle("Do you want it public?");

function deleteGlobalWaypoint(tag) {
    globalWaypoints.delete(tag);
}

const getGlobalWaypoints = () => {
    const globalWaypoints = new Set();
    const players = world.getPlayers().filter(plr => plr.getTags().find(tag => tag.startsWith("wp") && tag.match(/public/)));
    for (const player of players) {
        const publicWP = player.getTags().filter(tag => tag.match(/.+public/));
        for (const tag of publicWP) globalWaypoints.add(tag.slice(3));
    }
    return globalWaypoints;
};


const getMyWaypoints = player => new Set([...player.getTags().filter(tag => tag.startsWith("wp") && tag.match(/private/))].map(tag => tag.slice(3)));

const getAllMyWaypoints = player => new Set([...player.getTags().filter(tag => tag.startsWith("wp") && tag.match(/private|public/g))].map(tag => tag.slice(3)));

const getData = string => {
    if (string) {
        const replacedString = string.replace("wp:", "");
        return replacedString.split(/\|/);
    } else {
        return [];
    }
};

const globalWaypoints = getGlobalWaypoints();

world.afterEvents.itemUse.subscribe(({
    itemStack, source
}) => {
    if (itemStack.typeId == "sh:menu") showMenu(source, 'main');
});

function showMenu(player, menu) {
    const match = tag => tag.match(new RegExp(`.+\\|${player.name}`));
    const myWaypoints = getMyWaypoints(player);
    const globalWaypoints = getGlobalWaypoints();
    const allMyWaypoints = getAllMyWaypoints(player);
    switch (menu) {
        case "main":
            const form = new ActionFormData()
            .title('§lWAYPOINT MENU')
            .body('\n\n    \n\n     This addon was made by §lSHADOW     GAMER§r §cYOU§rTUBE : §a@shadowgamer100k')
            .button('§lCREATE TP',
                'textures/creat')
            .button('§lTELEPORT',
                'textures/Teleport')
            .button('§lDELETE',
                'textures/delete')
            .button('§lDETAILS',
                'textures/shadow')
            .show(player).then(({
                selection, canceled
            }) => {
                if (canceled) return;
                switch (selection) {
                    case 0:
                        showMenu(player, "create");
                        break;
                    case 1:
                        showMenu(player, "Teleport");
                        break;
                    case 2:
                        showMenu(player, "delete");
                        break
                    case 3:
                        player.sendMessage("This addon was made by §lSHADOW GAMER§r §cYOU§rTUBE : §a@shadowgamer100k");
                        player.playSound("random.pop");
                        break;
                }
            }).catch(e => console.error(e, e.stack));
            break;

        case "create":
            create.show(player).then(({
                formValues, canceled
            }) => {
                if (canceled) showMenu(player, 'main');
                const [name,
                    color,
                    state] = formValues;
                const exits_ = [...allMyWaypoints.values()].find(tag => getData(tag)[0] == name);
                if (myWaypoints.size == 1024) return player.sendMessage(`§cYou reached the maximum waypoints (§c${myWaypoints.size}§f/§a1024)`);
                if (!isNaN(Number(name))) return player.sendMessage("§cThe waypoint's name cannot starts with a number");
                if (!exits_) {
                    const {
                        x,
                        y,
                        z
                } = player.location;
                player.addTag(`wp:${name}|${player.name}|${player.dimension.id.split(/:/)[1]}|${Math.floor(x)},${Math.floor(y)},${Math.floor(z)}|${(state ? "public": "private")}`)
                const entity = player.dimension.spawnEntity("pa:tp_spawn", new Vector(x, y, z));
                entity.nameTag = `${colors.codes.split(/\|/)[color]}  ${name} \n§f${player.name}\n${Math.floor(x)} ${Math.floor(y)} ${Math.floor(z)}`;
                entity.addTag(name);
                player.sendMessage(`§l§bWaypoint§r ${colors.codes.split(/\|/)[color]} ${name} §f was created §asuccessfully as §7${(state ? "public": "private")}`);
                player.playSound("random.levelup", {
                    volume: 0.7, pitch: 0.7
            });
            } else {
                player.sendMessage(`§l§cWaypoint named '${name}' already exists.`);
                player.playSound("random.break");
            }
    }).catch(e => console.error(e, e.stack));
break;

case "Teleport":
    const Teleport = new ActionFormData()
    .title("Chose what you want")
    .body("")
    .button(`§lPRIVATE WAYPOINTS\n§r§o==> ${myWaypoints.size}/1024 <==`,
        'textures/private')
    .button('§lGLOBAL WAYPOINTS',
        'textures/public')
    .button("§lRETURN", "textures/RETURN/Retun.png");
    Teleport.show(player).then(({
        selection, canceled
    }) => {
        if (canceled) {
            return;
        };
        if (selection === 0) {
            showMenu(player, "privlist");
        };
        if (selection === 1) {
            showMenu(player, "publist");
        };
        if (selection === 2) {
         showMenu(player, 'main');
        };
}).catch(e => console.error(e, e.stack));
break;

case "privlist":
    const privlist = new ActionFormData()
    .title("§lSELECT A PLACE")
    .body(`§lThis are all your waypoints\nYou have §r§a ${myWaypoints.size} §r§lwaypoints`);
    if (myWaypoints?.size == 0 || !myWaypoints) return player.sendMessage("§4You haven't any §dprivate §cwaypoints");
    for (const tag of [...myWaypoints.values()]) {
        const nameP = getData(tag)[0];
        const Coordonnait = getData(tag)[3];
        const WhereThisWayp = getData(tag)[2];
        const ButtonText = `§l${nameP}§r\n§o§n==> ${Coordonnait} <==`
        let IconePath;
        if (WhereThisWayp === 'overworld') {
            IconePath = 'textures/WaypointPic/OVERWORLD.png';
        } else if (WhereThisWayp === 'nether') {
            IconePath = 'textures/WaypointPic/NETHER.png';
        } else if (WhereThisWayp === 'the_end') {
            IconePath = 'textures/WaypointPic/END.png';
        }

        privlist.button(ButtonText, IconePath);
    }
    privlist.show(player).then(({
        selection, canceled
    }) => {
        if (canceled) {
            return;
        }  else {
            let countdown = 2;
            const countdownInterval = system.runInterval(() => {
                countdown--;
        //ADD TP PARTICLES FUNCTION
                TPparticles(player);
                if (countdown < 0) {
                    system.clearRun(countdownInterval);
                    const [x,
                        y,
                        z] = getData([...myWaypoints.values()][selection])[3].split(/,/).map(coord => parseInt(coord));
                    player.teleport(new Vector(x, y, z), {
                        dimension: world.getDimension(`minecraft:${getData([...myWaypoints.values()][selection])[2]}`)
                    });
                    player.sendMessage(`§7You have been teleported to §r§l§f${getData([...myWaypoints.values()][selection])[0]}§r§5 waypoint`);
                    system.runTimeout(() => {
                        player.runCommandAsync(`inputpermission set @s movement enabled`);
                        player.playSound(`mob.endermen.portal`);
                    });
                }
            },
                5);
        }
    }).catch(e => console.error(e,
        e.stack));
    break;

case "publist":
    const publist = new ActionFormData()
    .title("§lGLOBAL WAYPOINTS")
    .body("§lFind all public waipoints here");
    for (const tag of [...globalWaypoints.values()]) {
        const waypointData = getData(tag);
        const dimension = waypointData[2];
        const creatorName = waypointData[1];
        let buttonTexture;
        if (dimension === 'overworld') {
            buttonTexture = 'textures/WaypointPic/OVERWORLD.png';
        } else if (dimension === 'nether') {
            buttonTexture = 'textures/WaypointPic/NETHER.png';
        } else if (dimension === 'the_end') {
            buttonTexture = 'textures/WaypointPic/END.png';
        }
        const TextButton = `${waypointData[0]}\n§o§n==> ${creatorName} <==`
        publist.button(TextButton, buttonTexture);
    }
    publist.show(player).then(({
        selection, canceled
    }) => {
        if (canceled) {
            return;
        } else {
            let coutdown = 2;
            const coutdownInterval = system.runInterval(() => {
                coutdown--;
    //ADD TP PARTICLES FUNCTION
               TPparticles(player);
                if (coutdown < 0) {
                    system.clearRun(coutdownInterval);
                    const [x,
                        y,
                        z] = getData([...globalWaypoints.values()][selection])[3].split(/,/).map(coord => parseInt(coord));
                    player.teleport(new Vector(x, y, z), {
                        dimension: world.getDimension(`minecraft:${getData([...globalWaypoints.values()][selection])[2]}`)
                    });
                    player.sendMessage(`You have been teleported to §r§l§f${getData([...globalWaypoints.values()][selection])[0]}§r§5 waypoint`);
                  /*  system.runTimeout(() => {
                        player.runCommand(`inputpermission set @s movement enabled`);
                    }); */
                }
            },
                5);
        }
    }).catch(e => console.error(e,
        e.stack));
    break;

case "delete":
    if (allMyWaypoints.size == 0) return player.sendMessage("§4You haven't§c waypoints");
    const deleteW = new ModalFormData()
    .title("§lDELETE SOME SPECIFIC WAYPOINT")
    .dropdown("Waypoints", [...allMyWaypoints.values()].map(tag => getData(tag)[0]), 0)
    .show(player).then(({
        formValues, canceled
    }) => {
        if (canceled) {
            showMenu(player, 'main')
        };
        const [index] = formValues;
        if (player.dimension.id !== `minecraft:${getData([...allMyWaypoints.values()][index])[2]}`) {
            const haveTo = new MessageFormData()
            .title("§lEntity is in another dimension")
            .body(`Are you sure to want to teleport to ${getData([...allMyWaypoints.values()][index])[2]} to go to delete it?\nYou can't delete entities aren't in your dimension.`)
            .button1("No")
            .button2("Yes")
            .show(player).then(({
                selection
            }) => {
                switch (selection) {
                    case 1:
                        const [x, y, z] = getData([...allMyWaypoints.values()][index])[3].split(/,/).map(coord => parseInt(coord));
                        player.teleport(new Vector(x, y, z), {
                            dimension: world.getDimension(`minecraft:${getData([...allMyWaypoints.values()][index])[2]}`)
                        });
                        break;
                    case 0:
                        showMenu(player, "delete");
                        break;
                    default:
                        break;
                }
            }).catch(e => console.error(e, e.stack));
        } else {
            const delete_ = new MessageFormData()
            .title("§lARE YOU SURE?")
            .body(`§lDo you really want to delete ${getData([...allMyWaypoints.values()][index])[0]} waypoint?`)
            .button1("No")
            .button2("Yes")
            .show(player).then(({
                selection, canceled
            }) => {
                if (canceled) return;
                switch (selection) {
                    case 1:
                        player.sendMessage(`§eWaypoint ${getData([...allMyWaypoints.values()][index])[0]} was deleted successfully`);
                        player.removeTag(`wp:${[...allMyWaypoints.values()][index]}`);
                        player.dimension.getEntities({
                            tags: [getData([...allMyWaypoints.values()][index])[0]]
                        })[0].kill();
                        deleteGlobalWaypoint([...allMyWaypoints.values()][index]);
                        player.playSound("random.levelup");
                        break;
                    case 0:
                        showMenu(player, "delete");
                        break;
                }
            }).catch(e => console.error(e, e.stack));
        }
    }).catch(e => console.error(e,
        e.stack));
    break;
}
}