import { ItemComponentUseOnEvent, Block, world } from '@minecraft/server'
import { onUseOnWrapper } from './wrapper.js';

export class FireLighter extends onUseOnWrapper {
    constructor() {
        super();
        this.portalManager = new PortalManager();
    }

    /**
     * @param {ItemComponentUseOnEvent} e 
     */
    onUseOn(e) {
        const player = e.source;
        const dimension = player.dimension;
        this.decrementDurability(player, e.itemStack, 1);

        dimension.playSound('fire.ignite', { ...e.block.location, ...e.block.location + 0.5 })

        const lightPortal = this.portalManager.onPortalBlockInteract(e);
        if (lightPortal) return;

        let location = e.block.above().center();
        location.y -= 0.5;

        if (dimension.getBlock(location).typeId !== 'minecraft:air') return;

        const nearbyFireEntities = dimension.getEntitiesAtBlockLocation(location);
        if (nearbyFireEntities.some(entity => entity.typeId === 'plank_waao:soul_fire')) return;
        dimension.spawnEntity('plank_waao:soul_fire', location);
    }
}



const overworld = world.getDimension('overworld');

class PortalManager {
    constructor() { }

    /**
     * 
     * @param {ItemComponentUseOnEvent} e 
     * @returns {boolean} if the portal was successful
     */
    onPortalBlockInteract(e) {
        if (e.block.typeId !== 'minecraft:reinforced_deepslate') return;

        const portalEntities = overworld.getEntities({ type: 'plank_waao:portal_visual', location: e.block.location, maxDistance: 32 });
        if (portalEntities.length > 0) return true; // decremenet durability but don't light portal

        const connectedBlocks = this.#collectConnectedFrameBlocks(e.block.location);
        const frameBounds = this.#getFrameBounds(connectedBlocks);
        const isValidFrame = this.#verifyFrameDimensions(frameBounds);

        if (!isValidFrame || !this.#verifyFrameIntegrity(frameBounds)) return;

        const orientation = this.#getFrameOrientation(frameBounds);

        const lowestX = frameBounds.minX;
        const lowestY = frameBounds.minY;
        const lowestZ = frameBounds.minZ;

        if (orientation == 'x') {
            overworld.spawnEntity('plank_waao:portal_visual', { x: lowestX + 1, y: lowestY + 1, z: lowestZ });
            overworld.spawnEntity('plank_waao:void_beast', {
                x: lowestX + 11,
                y: lowestY + 1,
                z: lowestZ,
            })
        } else {
            overworld.spawnEntity('plank_waao:portal_visual', { x: lowestX, y: lowestY + 1, z: lowestZ + 1 })
                .triggerEvent('plank_waao:p.z_axis');
            overworld.spawnEntity('plank_waao:void_beast', {
                x: lowestX,
                y: lowestY + 1,
                z: lowestZ + 11,
            }).setRotation({ x: 0, y: 90 });
        }



        return true;

    }

    #getFrameOrientation(frameBlocks) {
        const lengthX = frameBlocks.maxX - frameBlocks.minX;
        const lengthZ = frameBlocks.maxZ - frameBlocks.minZ;

        return lengthX > lengthZ ? 'x' : 'z';
    }

    /**
     * 
     * @param {location} location 
     * @returns {Block[]}
     */
    #collectConnectedFrameBlocks(location) {
        const visited = new Set();
        const queue = [];
        const frameBlocks = [];

        queue.push(location);
        visited.add(`${location.x},${location.y},${location.z}`);

        while (queue.length > 0) {
            const blockLocation = queue.shift();
            const block = overworld.getBlock(blockLocation);
            frameBlocks.push(block);

            const adjacentBlocks = this.#getAdjacentFrameBlocks(blockLocation);
            for (const adjBlock of adjacentBlocks) {
                const key = `${adjBlock.location.x},${adjBlock.location.y},${adjBlock.location.z}`;
                if (!visited.has(key)) {
                    visited.add(key);
                    queue.push(adjBlock.location);
                }
            }
        }

        return frameBlocks;
    }

    /**
     * 
     * @param {location} block 
     * @returns {Block[]}
     */
    #getAdjacentFrameBlocks(block) {
        const adjacentOffsets = [
            { x: 1, y: 0, z: 0 },
            { x: -1, y: 0, z: 0 },
            { x: 0, y: 1, z: 0 },
            { x: 0, y: -1, z: 0 },
            { x: 0, y: 0, z: 1 },
            { x: 0, y: 0, z: -1 },
        ];

        const adjacentBlocks = [];

        for (const offset of adjacentOffsets) {
            const x = block.x + offset.x;
            const y = block.y + offset.y;
            const z = block.z + offset.z;
            const adjBlock = overworld.getBlock({ x, y, z });
            if (adjBlock && adjBlock.typeId === 'minecraft:reinforced_deepslate') {
                adjacentBlocks.push(adjBlock);
            }
        }

        return adjacentBlocks;
    }

    #getFrameBounds(frameBlocks) {
        const xs = frameBlocks.map(b => b.x);
        const ys = frameBlocks.map(b => b.y);
        const zs = frameBlocks.map(b => b.z);

        return {
            minX: Math.min(...xs),
            maxX: Math.max(...xs),
            minY: Math.min(...ys),
            maxY: Math.max(...ys),
            minZ: Math.min(...zs),
            maxZ: Math.max(...zs),
        };
    }

    #verifyFrameDimensions(bounds) {
        const height = bounds.maxY - bounds.minY + 1;
        const lengthX = bounds.maxX - bounds.minX + 1;
        const lengthZ = bounds.maxZ - bounds.minZ + 1;

        const lengths = [lengthX, lengthZ].sort((a, b) => b - a);

        const isValidHeight = height === 8;
        const isValidLength = lengths[0] === 22 && lengths[1] === 1;

        return isValidHeight && isValidLength;
    }


    #verifyFrameIntegrity(bounds) {
        const frameEdges = this.#getFrameEdgeCoordinates(bounds);

        for (const coord of frameEdges) {
            const block = overworld.getBlock(coord);
            if (!block || !block.typeId === 'minecraft:reinforced_deepslate') {
                return false;
            }
        }

        return true;
    }

    #getFrameEdgeCoordinates(bounds) {
        const coords = [];

        // Determine orientation
        const isAlongX = bounds.maxX - bounds.minX > bounds.maxZ - bounds.minZ;

        // Vertical edges
        for (let y = bounds.minY; y <= bounds.maxY; y++) {
            if (isAlongX) {
                coords.push({ x: bounds.minX, y, z: bounds.minZ });
                coords.push({ x: bounds.maxX, y, z: bounds.minZ });
            } else {
                coords.push({ x: bounds.minX, y, z: bounds.minZ });
                coords.push({ x: bounds.minX, y, z: bounds.maxZ });
            }
        }

        // Horizontal edges (top and bottom)
        const yLevels = [bounds.minY, bounds.maxY];
        for (const y of yLevels) {
            if (isAlongX) {
                for (let x = bounds.minX; x <= bounds.maxX; x++) {
                    coords.push({ x, y, z: bounds.minZ });
                }
            } else {
                for (let z = bounds.minZ; z <= bounds.maxZ; z++) {
                    coords.push({ x: bounds.minX, y, z });
                }
            }
        }

        return coords;
    }
}

//const portalManager = new PortalManager();



/**
 * @typedef location
 * @property {number} x
 * @property {number} y
 * @property {number} z
 */



