import { world, system, MolangVariableMap } from "@minecraft/server";
import { ActionFormData } from '@minecraft/server-ui';

let radarStructures = []; // Array to store structure data

world.beforeEvents.worldInitialize.subscribe((data) => {
    const { itemComponentRegistry } = data;
    itemComponentRegistry.registerCustomComponent("pm_m8:ruins_radar", {
        onUse: (data) => {
            const { source } = data;
            source.sendMessage(`Activating the radar...`);

            // Clear the array each time radar is used
            radarStructures = [];

            // Get all dynamic properties that start with 'pm_m8:str_'
            const propertyIds = world.getDynamicPropertyIds();
            const structuresMap = new Map();

            for (const propertyId of propertyIds) {
                if (propertyId.startsWith('pm_m8:str_')) {
                    const structureLocation = world.getDynamicProperty(propertyId);
                    // console.warn(`propertyId: ${propertyId}`);
                    if (source.hasTag(`log`)) {
                        source.sendMessage(`propertyId: ${propertyId}`);
                    }
                    if (structureLocation) {
                        const suffix = propertyId.slice(10); // 去掉前缀 'pm_m8:str_'
                        // console.warn(`suffix: ${suffix}`);

                        // 手动解析 suffix
                        if (suffix.length === 9) {
                            const abbr = suffix.substring(0, 3); // 前 3 个字符为缩写
                            const sequenceNumber = suffix.substring(3, 7); // 接下来的 4 个字符为序列号
                            const hasBoss = suffix.charAt(8); // 最后一个字符为 Boss 标志

                            // console.warn(`abbr: ${abbr}, sequenceNumber: ${sequenceNumber}, hasBoss: ${hasBoss}`);

                            if ((abbr === 'bas' || abbr === 'mce') || hasBoss === 't') { // Allow Growth Center and Medical Center regardless of boss flag
                                let structureName;
                                switch (abbr) {
                                    case 'afa': structureName = 'Abandoned Factory'; break;
                                    case 'mce': structureName = 'Medical Center'; break;
                                    case 'mcv': structureName = 'Monster Cave'; break;
                                    case 'mnr': structureName = 'Monster Nest Ruins'; break;
                                    case 'otp': structureName = 'Outpost'; break;
                                    case 'rlb': structureName = 'Research Laboratory'; break;
                                    case 'sws': structureName = 'Subway Station'; break;
                                    case 'bas': structureName = '§aGrowth Center'; break;
                                    default: structureName = 'Unknown Structure'; break;
                                }
                                const distance = calculateDistance(source.location, structureLocation);

                                // 如果距离超过 2048 格 而且 不是基地
                                if (distance > 2048 && (abbr !== 'bas')) {
                                    continue;
                                }

                                if (!structuresMap.has(structureName) || distance < structuresMap.get(structureName).distance) {
                                    structuresMap.set(structureName, {
                                        name: structureName,
                                        x: Math.round(structureLocation.x),
                                        y: Math.round(structureLocation.y),
                                        z: Math.round(structureLocation.z),
                                        distance: distance
                                    });
                                }
                            }
                        } else {
                            // console.warn(`Property ID ${propertyId} does not match expected format.`);
                        }
                    }
                }
            }

            radarStructures = Array.from(structuresMap.values());

            if (!radarStructures.length) {
                source.sendMessage(`No structure found near your location.`);
            } else {
                processRadarData(source);
            }
        }
    });
});

function calculateDistance(playerLocation, structureLocation) {
    return Math.sqrt(
        Math.pow(playerLocation.x - structureLocation.x, 2) +
        Math.pow(playerLocation.y - structureLocation.y, 2) +
        Math.pow(playerLocation.z - structureLocation.z, 2)
    );
}

function processRadarData(player) {
    let message = " ".repeat(30) + `Found §a§l${radarStructures.length} Structures§r near your location. Select one to locate.`;

    const form = new ActionFormData()
        .title(`ck.radar.`)
        .body(message);

    // Add a button for each structure in `radarStructures`
    radarStructures.forEach((structure) => {
        form.button(structure.name, "ui/task_ui/skill_icon_holder");
    });

    form.show(player).then(response => {
        if (response.canceled) return;

        const selection = response.selection;
        if (selection === undefined) return;
        if (selection >= radarStructures.length) return;

        // Get the selected structure and pass its coordinates back into the function
        const structure = radarStructures[selection];
        processData(player, { x: structure.x, y: structure.y, z: structure.z });
    });
}

function processData(player, location) {
    // Format the coordinates if location is provided
    let coordinates = `X:${location.x}, Y:${location.y}, Z:${location.z}`;
    let structure = radarStructures.find(structure => structure.x === location.x && structure.y === location.y && structure.z === location.z);
    let distance = calculateDistance(player.location, location);
    let realMessage = `Target selected: §a§l${structure.name}§r, Distance: approximately §a§l${Math.round(distance)} blocks§r.`;

    // Pad coordinates to always be 30 characters
    let paddedCoordinates = coordinates.padEnd(30, '^');
    let message = paddedCoordinates + realMessage;

    const form = new ActionFormData()
        .title(`ck.radar.`)
        .body(message);

    // Add buttons with new labels
    form.button('Locate This Structure', "ui/task_ui/skill_icon_holder");
    form.button('Stop Current Locating', "ui/task_ui/skill_icon_holder");
    form.button('§cBack', "ui/task_ui/skill_icon_holder");

    form.show(player).then(response => {
        if (response.canceled) return;

        const selection = response.selection;
        if (selection === undefined) return;

        switch (selection) {
            case 0: // Locate This Structure
                if (!player.hasTag('pd:locate_structure')) {
                    player.addTag('pd:locate_structure');
                }
                else {
                    player.removeTag('pd:locate_structure');
                    player.addTag('pd:locate_structure');
                }
                player.sendMessage(`Starting to locate §a${structure.name}§r, approximately §a${Math.round(distance)} blocks§r away.`);
                locator(player, { x: location.x+10, y: location.y+10, z: location.z+10 });
                break;
            case 1: // Stop Current Location
                if (player.hasTag('pd:locate_structure')) {
                    player.removeTag('pd:locate_structure');
                    player.sendMessage('§eRadar location stopped.');
                }
                break;
            case 2: // Back
                processRadarData(player);
                break;
            default:
                break;
        }
    });
}

function locator(source, structureLocation) {
    let isMoving = false;
    let i = 0;
    const lt = system.runInterval(() => {
        if (source.hasTag('pd:locate_structure') && !isMoving) {
            isMoving = true;
            locateEntity(source, structureLocation, 'minecraft:endrod');
        }
        if (!source.hasTag('pd:locate_structure')) {
            system.clearRun(lt);
        }
        if (i === 115) {
            isMoving = false;
        }
        i = (i + 1) % 120;
    }, 1);
}

function locateEntity(player, to, particle) {
    // Calculate the distance between the two points
    const from = player.getHeadLocation();
    const distance = Math.sqrt(Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2) + Math.pow(to.z - from.z, 2));

    // If the player is within 2 units of the target, remove the tag and stop
    if (distance < 20) {
        player.removeTag('pd:locate_structure');
        player.sendMessage(`Target structure nearby: §a${to.x}, ${to.y}, ${to.z}§r.`);
        player.sendMessage(`§eRadar location stopped.`);
        return;
    }

    // Calculate the direction vector and fix the Y level to player's current height
    const direction = { x: to.x - from.x, y: 0, z: to.z - from.z };
    const magnitude = Math.sqrt(Math.pow(direction.x, 2) + Math.pow(direction.z, 2));

    if (magnitude === 0) return; // If the player is already at the target, stop

    const normalizedDirection = {
        x: direction.x / magnitude,
        y: 0, // Keep y level fixed
        z: direction.z / magnitude
    };

    // Adjust the start location (2 blocks in front of the player)
    const startLocation = {
        x: from.x + normalizedDirection.x * 2,
        y: from.y, // Maintain y level
        z: from.z + normalizedDirection.z * 2
    };

    // Set the number of steps to control particle movement speed
    const steps = Math.ceil(magnitude / 2);

    function spawnParticles(step = 0) {
        // Check if the player still has the tag
        if (!player.hasTag('pd:locate_structure')) {
            return; // Stop the particle spawning if the tag is removed
        }

        const particleLocation = {
            x: startLocation.x + normalizedDirection.x * step * 2, // Move 2 units per step
            y: from.y - 1, // Keep the same y level
            z: startLocation.z + normalizedDirection.z * step * 2
        };

        const molangMap = new MolangVariableMap();
        molangMap.setFloat("facingx", normalizedDirection.x);
        molangMap.setFloat("facingy", 0); // No vertical movement
        molangMap.setFloat("facingz", normalizedDirection.z);

        // Delay the particle spawning to create a moving effect
        system.runTimeout(() => {
            try {
                // Check the tag again right before spawning the particle
                if (player.hasTag('pd:locate_structure')) {
                    player.dimension.spawnParticle(particle, particleLocation);
                }
            } catch (error) {
                // Uncomment to log particle spawn errors
                // console.warn(`Couldn't spawn particle at ${particleLocation.x}, ${particleLocation.y}, ${particleLocation.z}: ${error}`);
            }

            // Continue spawning particles with a delay
            spawnParticles(step + 1);
        }, 5); // 100ms delay between each particle
    }

    // Start spawning particles
    spawnParticles();
}