import { world, system } from "@minecraft/server";
import { playTTAVMediumExplosionSounds } from "../TTAVMediumExplosionSoundHandler.js";

export const missileStates = new Map();
export const missileVelocities = new Map();
export const tickingAreaNames = new Map();
export const activeTickingAreas = new Set();
export let nextTickingAreaId = 1;

export const MISSILE_TYPE = "ttav:homing_missile";
export const MISSILE_SPEED = 2;
export const SCAN_RADIUS = 300;
export const EXPLOSION_RADIUS_CHECK = 1;
export const LAUNCH_DURATION = 30; 
export const LAUNCH_SPEED = 0.5;

export const dimensions = [
    "minecraft:overworld",
    "minecraft:nether",
    "minecraft:the_end"
];

system.runInterval(() => {
    for (const dimId of dimensions) {
        const dimension = world.getDimension(dimId);
        if (!dimension) continue;
        
        const missiles = dimension.getEntities({ type: MISSILE_TYPE });
        for (const missile of missiles) {
            updateMissile(missile);
        }
    }
}, 1);

function updateMissile(missile) {
    if (!missile || !missile.isValid()) return;

    updateTickingArea(missile);
    
    const state = missileStates.get(missile.id) ?? initializeMissileState(missile);
    const velocity = missileVelocities.get(missile.id) ?? { x: 0, y: 0, z: 0 };

    if (state.isLaunching) {
        handleMissileLaunch(missile, state);
        return;
    }

    const target = findNearestTarget(missile);
    if (!target) return;

    const currentBlock = missile.dimension.getBlock({
        x: Math.floor(missile.location.x),
        y: Math.floor(missile.location.y),
        z: Math.floor(missile.location.z)
    });

    if (currentBlock?.typeId !== "minecraft:air" && 
        !currentBlock?.typeId.startsWith("minecraft:light_block_")) {
        explodeMissile(missile);
        return;
    }

    const dx = target.location.x - missile.location.x;
    const dy = target.location.y - missile.location.y;
    const dz = target.location.z - missile.location.z;

    const magnitude = Math.sqrt(dx * dx + dy * dy + dz * dz);
    if (magnitude <= EXPLOSION_RADIUS_CHECK) {
        explodeMissile(missile);
        return;
    }

    const dirX = dx / magnitude;
    const dirY = dy / magnitude;
    const dirZ = dz / magnitude;

    velocity.x += (dirX * MISSILE_SPEED - velocity.x) * 0.2;
    velocity.y += (dirY * MISSILE_SPEED - velocity.y) * 0.2;
    velocity.z += (dirZ * MISSILE_SPEED - velocity.z) * 0.2;

    const newX = missile.location.x + velocity.x;
    const newY = missile.location.y + velocity.y;
    const newZ = missile.location.z + velocity.z;

    const destinationBlock = missile.dimension.getBlock({
        x: Math.floor(newX),
        y: Math.floor(newY),
        z: Math.floor(newZ)
    });

    if (destinationBlock?.typeId !== "minecraft:air" && 
        !destinationBlock?.typeId.startsWith("minecraft:light_block")) {
        explodeMissile(missile);
        return;
    }

    const yaw = Math.atan2(velocity.z, velocity.x) * 180 / Math.PI - 90;
    const pitch = -Math.atan2(velocity.y, Math.sqrt(velocity.x * velocity.x + velocity.z * velocity.z)) * 180 / Math.PI;
    missile.setRotation({ x: pitch, y: yaw });

    missile.teleport(
        { x: newX, y: newY, z: newZ },
        { dimension: missile.dimension }
    );

    missileStates.set(missile.id, state);
    missileVelocities.set(missile.id, velocity);
}

function handleMissileLaunch(missile, state) {
    const currentPos = missile.location;
    
    const currentBlock = missile.dimension.getBlock({
        x: Math.floor(currentPos.x),
        y: Math.floor(currentPos.y),
        z: Math.floor(currentPos.z)
    });

    if (currentBlock?.typeId !== "minecraft:air") {
        explodeMissile(missile);
        return;
    }

    missile.teleport(
        {
            x: currentPos.x,
            y: currentPos.y + LAUNCH_SPEED,
            z: currentPos.z
        },
        {
            dimension: missile.dimension
        }
    );

    state.launchTicks++;
    if (state.launchTicks >= LAUNCH_DURATION) {
        state.isLaunching = false;
    }

    missileStates.set(missile.id, state);
}

function updateTickingArea(missile) {
    if (!missile || !missile.isValid()) return;

    const x = Math.floor(missile.location.x);
    const y = Math.floor(missile.location.y);
    const z = Math.floor(missile.location.z);

    let areaName = tickingAreaNames.get(missile.id);
    if (!areaName) {
        areaName = `hm${nextTickingAreaId++}`;
        if (nextTickingAreaId > 100) nextTickingAreaId = 1;
        tickingAreaNames.set(missile.id, areaName);
        
    }

    try {
        const dimension = missile.dimension;
        if (dimension) {
            dimension.runCommand(`tickingarea remove ${areaName}`);
            dimension.runCommand(`tickingarea add circle ${x} ${y} ${z} 2 ${areaName}`);
            activeTickingAreas.add(areaName);
            
        }
    } catch (error) {
        
    }
}

function initializeMissileState(missile) {
    return {
        initialized: true,
        startTime: Date.now(),
        launchTicks: 0,
        isLaunching: true
    };
}

function findNearestTarget(missile) {
    const targets = missile.dimension.getEntities({
        location: missile.location,
        maxDistance: SCAN_RADIUS,
        families: ["laser_target"]
    });

    let nearest = null;
    let minDistance = SCAN_RADIUS;

    for (const target of targets) {
        const distance = calculateDistance(missile.location, target.location);
        if (distance < minDistance) {
            minDistance = distance;
            nearest = target;
        }
    }

    return nearest;
}

function calculateDistance(locA, locB) {
    const dx = locB.x - locA.x;
    const dy = locB.y - locA.y;
    const dz = locB.z - locA.z;
    return Math.sqrt(dx * dx + dy * dy + dz * dz);
}

function explodeMissile(missile) {
    try {
        
        const areaName = tickingAreaNames.get(missile.id);
        const dimension = missile.dimension;
        
        missile.triggerEvent("on_hit");
        playTTAVMediumExplosionSounds(missile);
        
        if (areaName && dimension) {
            system.runTimeout(() => {
                try {
                    dimension.runCommand(`tickingarea remove ${areaName}`);
                    activeTickingAreas.delete(areaName);
                    tickingAreaNames.delete(missile.id);
                } catch (error) {
                    
                }
            }, 1);
        }
        
        cleanupMissile(missile.id);
    } catch (error) {
        
    }
}

function cleanupMissile(missileId) {
    
    const areaName = tickingAreaNames.get(missileId);
    
    if (areaName) {
        for (const dimId of dimensions) {
            const dimension = world.getDimension(dimId);
            if (dimension) {
                system.runTimeout(() => {
                    try {
                        dimension.runCommand(`tickingarea remove ${areaName}`);
                    } catch (e) {}
                }, 1);
            }
        }
    }
    
    system.runTimeout(() => {
        activeTickingAreas.delete(areaName);
        missileStates.delete(missileId);
        missileVelocities.delete(missileId);
        tickingAreaNames.delete(missileId);
    }, 2);
}

world.afterEvents.playerSpawn.subscribe((ev) => {
    
    
    for (const dimId of dimensions) {
        const dimension = world.getDimension(dimId);
        if (!dimension) continue;

        for (const areaName of activeTickingAreas) {
            system.runTimeout(() => {
                try {
                    dimension.runCommand(`tickingarea remove ${areaName}`);
                } catch (e) {}
            }, 1);
        }

        for (let i = 1; i <= 100; i++) {
            system.runTimeout(() => {
                try {
                    dimension.runCommand(`tickingarea remove hm${i}`);
                } catch (e) {}
            }, 1);
        }
    }
    
    activeTickingAreas.clear();
    tickingAreaNames.clear();
    nextTickingAreaId = 1;
});