/**
 * Catapult.js
 * Enemy that launches boulders and stone rain at Mario
 * Catapults appear in level 4+, Onagers (stronger) in level 5+
 */

export class Catapult {
    /**
     * Generate catapults for a level
     * @param {Object} level - Level data
     * @param {number} levelIndex - Level index
     * @param {number} levelWidth - Width of the level
     * @param {number} canvasHeight - Canvas height
     * @returns {Array} - Array of catapult objects
     */
    static generate(level, levelIndex, levelWidth, canvasHeight) {
        const catapults = [];

        let catapultCount = 1; // Always 1 catapult for level 4+
        let onagerCount = 0;

        // Level 5+ gets onagers
        if (levelIndex >= 4) {
            onagerCount = 1; // 1 onager for level 5+
        }

        const totalCount = catapultCount + onagerCount;
        console.log(`🏹 Generating ${catapultCount} catapult(s) and ${onagerCount} onager(s) for level ${levelIndex + 1}`);

        for (let i = 0; i < totalCount; i++) {
            const isOnager = i >= catapultCount; // Onagers come after catapults

            // Place catapults near END of level
            const nearEndX = levelWidth * 0.7; // 70% through level
            const catapultX = nearEndX + (i * 300) + Math.random() * 200;
            let catapultY = canvasHeight - 100; // Default: on background ground

            // Check if there's a platform, wall, or stair above this position
            const platformAbove = this._findPlatformAbove(catapultX, catapultY, level.platforms || []);
            const wallAbove = this._findWallAbove(catapultX, catapultY, level.walls || []);
            const stairAbove = this._findStairAbove(catapultX, catapultY, level.stairs || []);

            // Choose the lowest obstacle (closest to ground = highest Y value)
            const obstacles = [platformAbove, wallAbove, stairAbove].filter(obs => obs !== null);

            if (obstacles.length > 0) {
                const obstacleAbove = obstacles.reduce((lowest, current) =>
                    current.y > lowest.y ? current : lowest
                );
                catapultY = obstacleAbove.y - 80; // 80 is catapult height
                console.log(`🏹 Catapult moved to obstacle at y=${catapultY.toFixed(0)}`);
            }

            catapults.push({
                x: catapultX,
                y: catapultY,
                width: 60,
                height: 80,
                color: isOnager ? '#654321' : '#8B4513',
                lastShot: 0,
                shootCooldown: isOnager ? 6000 + Math.random() * 2000 : 4000 + Math.random() * 2000,
                type: isOnager ? 'onager' : 'catapult',
                isOnager: isOnager,
                armAngle: 0 // For rendering
            });

            console.log(`${isOnager ? '🏛️' : '🏹'} ${isOnager ? 'Onager' : 'Catapult'} placed at x=${catapultX.toFixed(0)}, y=${catapultY.toFixed(0)}`);
        }

        return catapults;
    }

    /**
     * Find platform above a position
     */
    static _findPlatformAbove(x, groundY, platforms) {
        let bestPlatform = null;
        let lowestY = 0;

        platforms.forEach(platform => {
            const catapultLeft = x;
            const catapultRight = x + 60;
            const platformLeft = platform.x;
            const platformRight = platform.x + platform.width;

            const hasHorizontalOverlap = catapultLeft < platformRight && catapultRight > platformLeft;

            if (hasHorizontalOverlap && platform.y < groundY && platform.y > lowestY) {
                bestPlatform = platform;
                lowestY = platform.y;
            }
        });

        return bestPlatform;
    }

    /**
     * Find wall above a position
     */
    static _findWallAbove(x, groundY, walls) {
        let bestWall = null;
        let lowestY = 0;

        walls.forEach(wall => {
            const catapultLeft = x;
            const catapultRight = x + 60;
            const wallLeft = wall.x;
            const wallRight = wall.x + wall.width;

            const hasHorizontalOverlap = catapultLeft < wallRight && catapultRight > wallLeft;

            if (hasHorizontalOverlap && wall.y < groundY && wall.y > lowestY) {
                bestWall = wall;
                lowestY = wall.y;
            }
        });

        return bestWall;
    }

    /**
     * Find stair above a position
     */
    static _findStairAbove(x, groundY, stairs) {
        let bestStair = null;
        let lowestY = 0;

        stairs.forEach(stair => {
            const catapultLeft = x;
            const catapultRight = x + 60;
            const stairLeft = stair.x;
            const stairRight = stair.x + stair.width;

            const hasHorizontalOverlap = catapultLeft < stairRight && catapultRight > stairLeft;

            if (hasHorizontalOverlap && stair.y < groundY && stair.y > lowestY) {
                bestStair = stair;
                lowestY = stair.y;
            }
        });

        return bestStair;
    }

    /**
     * Update all catapults
     * @param {Array} catapults - Array of catapults
     * @param {Object} mario - Mario object
     * @param {Array} boulders - Boulders array
     * @param {Array} stones - Stones array (for onagers)
     * @param {Function} playSound - Sound callback
     */
    static update(catapults, mario, boulders, stones, playSound, canvasHeight) {
        const currentTime = Date.now();

        catapults.forEach(catapult => {
            // Arm animation
            catapult.armAngle = Math.sin(Date.now() / 200) * 0.2;

            // Check if it's time to shoot
            if (currentTime - catapult.lastShot > catapult.shootCooldown) {
                // ONAGER: Check minimum range - don't fire if Mario is too close
                if (catapult.isOnager) {
                    const distanceToMario = Math.abs(catapult.x - mario.x);
                    const minimumRange = 300;

                    if (distanceToMario < minimumRange) {
                        console.log(`🏛️ Onager held fire - Mario too close! Distance: ${distanceToMario.toFixed(0)}px`);
                        return;
                    }
                }

                // Target Mario's position with imperfect aim
                const aimOffset = 100 + Math.random() * 150; // 100-250 pixel spread
                const aimDirection = Math.random() < 0.5 ? -1 : 1;
                const targetX = mario.x + (aimOffset * aimDirection);
                const targetY = canvasHeight - 50; // Ground level

                if (catapult.isOnager) {
                    // ONAGER: Fire 8 small stones in spread pattern with parabolic trajectory
                    for (let stone = 0; stone < 8; stone++) {
                        const randomSpreadX = (Math.random() - 0.5) * 400; // ±200px spread
                        const randomSpreadY = (Math.random() - 0.5) * 100; // ±50px spread
                        const stoneTargetX = targetX + randomSpreadX;
                        const stoneTargetY = targetY + randomSpreadY;

                        // Calculate parabolic trajectory
                        const deltaX = stoneTargetX - catapult.x;
                        const deltaY = stoneTargetY - catapult.y;
                        const time = 5 + Math.random() * 2; // 5-7 seconds flight time
                        const velocityX = deltaX / (time * 60);
                        const velocityY = (deltaY - 0.5 * 0.015 * time * time * 60 * 60) / (time * 60);

                        stones.push({
                            x: catapult.x + 30 + (Math.random() - 0.5) * 20,
                            y: catapult.y - 10 + (Math.random() - 0.5) * 10,
                            width: 8,
                            height: 8,
                            velocityX: velocityX,
                            velocityY: velocityY,
                            color: '#A0522D',
                            type: 'stone',
                            sourceCatapultX: catapult.x,
                            sourceCatapultY: catapult.y
                        });
                    }

                    catapult.lastShot = currentTime;
                    if (playSound) playSound('enemy_defeat');
                    console.log(`🏛️ Onager fired 8 stones in spread pattern!`);
                } else {
                    // CATAPULT: Fire single boulder with parabolic trajectory
                    const deltaX = targetX - catapult.x;
                    const deltaY = targetY - catapult.y;
                    const time = 7.5; // 7.5 seconds flight time
                    const velocityX = deltaX / (time * 60);
                    const velocityY = (deltaY - 0.5 * 0.01 * time * time * 60 * 60) / (time * 60);

                    boulders.push({
                        x: catapult.x + 30,
                        y: catapult.y - 10,
                        width: 25,
                        height: 25,
                        velocityX: velocityX,
                        velocityY: velocityY,
                        color: '#696969',
                        type: 'boulder',
                        hasLanded: false,
                        sourceCatapultX: catapult.x,
                        sourceCatapultY: catapult.y,
                        health: 2,
                        maxHealth: 2
                    });

                    catapult.lastShot = currentTime;
                    if (playSound) playSound('jump');
                    console.log(`🏹 Catapult fired boulder towards x=${targetX.toFixed(0)}`);
                }
            }
        });
    }

    /**
     * Update boulders
     * @param {Array} boulders - Array of boulders
     * @param {Object} mario - Mario object
     * @param {Array} platforms - Platforms for collision
     * @param {Array} walls - Walls for collision
     * @param {Function} onImpact - Callback when boulder hits something
     * @returns {Array} - Updated boulders array
     */
    static updateBoulders(boulders, mario, platforms, walls, onImpact) {
        if (!boulders || !Array.isArray(boulders)) return;

        const GRAVITY = 0.01; // Ultra-light gravity for parabolic arc
        const canvasHeight = 690; // Default canvas height

        // Iterate backwards to safely remove boulders
        for (let index = boulders.length - 1; index >= 0; index--) {
            const boulder = boulders[index];

            if (boulder.hasLanded) continue; // Don't update landed boulders

            // Apply physics
            boulder.velocityY += GRAVITY;
            boulder.x += boulder.velocityX;
            boulder.y += boulder.velocityY;

            // Check ground collision
            const groundLevel = canvasHeight - 50;
            if (boulder.y + boulder.height >= groundLevel) {
                if (onImpact) {
                    onImpact(boulder, index, boulder.x, groundLevel - boulder.height, null, -1, 'ground');
                }
                continue;
            }

            let hasHit = false;

            // Check collision with platforms
            platforms.forEach((platform, platformIndex) => {
                if (!hasHit && this._isCollidingRectRect(boulder, platform)) {
                    if (onImpact) {
                        onImpact(boulder, index, boulder.x, platform.y - boulder.height, platform, platformIndex, 'platform');
                    }
                    hasHit = true;
                }
            });

            // Check collision with walls (boulder destroys wall)
            if (!hasHit) {
                walls.forEach((wall, wallIndex) => {
                    if (!hasHit && this._isCollidingRectRect(boulder, wall)) {
                        if (onImpact) {
                            onImpact(boulder, index, boulder.x, boulder.y, wall, wallIndex, 'wall');
                        }
                        hasHit = true;
                    }
                });
            }

            // Check collision with Mario
            if (!hasHit && this._isCollidingRectRect(boulder, mario)) {
                if (onImpact) {
                    onImpact(boulder, index, boulder.x, boulder.y, mario, -1, 'mario');
                }
                hasHit = true;
                continue;
            }

            // Remove boulders that go off-screen
            if (boulder.x < -100 || boulder.x > 4000 || boulder.y > canvasHeight + 100) {
                boulders.splice(index, 1);
            }
        }
    }

    /**
     * Update stones (stone rain)
     * @param {Array} stones - Array of stones
     * @param {Object} mario - Mario object
     * @param {Array} platforms - Platforms for collision
     * @param {Function} onImpact - Callback when stone hits something
     * @returns {Array} - Updated stones array
     */
    static updateStones(stones, mario, platforms, onImpact) {
        if (!stones || !Array.isArray(stones)) return [];

        const GRAVITY = 0.015; // Lighter gravity for parabolic arc
        const canvasHeight = 690;
        const updatedStones = [];

        stones.forEach((stone, index) => {
            // Apply physics
            stone.velocityY += GRAVITY;
            stone.x += stone.velocityX;
            stone.y += stone.velocityY;

            // Check ground collision
            const groundLevel = canvasHeight - 50;
            if (stone.y + stone.height >= groundLevel) {
                if (onImpact) {
                    onImpact(stone, index, 'ground');
                }
                return; // Don't keep this stone
            }

            let hasHit = false;

            // Check collision with platforms
            platforms.forEach(platform => {
                if (!hasHit && this._isCollidingRectRect(stone, platform)) {
                    if (onImpact) {
                        onImpact(stone, index, 'platform');
                    }
                    hasHit = true;
                }
            });

            // Check collision with Mario
            if (!hasHit && this._isCollidingRectRect(stone, mario)) {
                if (onImpact) {
                    onImpact(stone, index, 'mario');
                }
                hasHit = true;
                return; // Don't keep this stone
            }

            // Keep stone if not hit and still on screen
            if (!hasHit && stone.x >= -100 && stone.x <= 4000 && stone.y <= canvasHeight + 100) {
                updatedStones.push(stone);
            }
        });

        return updatedStones;
    }

    /**
     * Circle-Rectangle collision detection
     */
    static _isCollidingCircleRect(circle, rect) {
        const closestX = Math.max(rect.x, Math.min(circle.x, rect.x + rect.width));
        const closestY = Math.max(rect.y, Math.min(circle.y, rect.y + rect.height));

        const distanceX = circle.x - closestX;
        const distanceY = circle.y - closestY;

        const distanceSquared = distanceX * distanceX + distanceY * distanceY;
        return distanceSquared < (circle.radius * circle.radius);
    }

    /**
     * Rectangle-Rectangle collision detection
     */
    static _isCollidingRectRect(rect1, rect2) {
        return rect1.x < rect2.x + rect2.width &&
               rect1.x + rect1.width > rect2.x &&
               rect1.y < rect2.y + rect2.height &&
               rect1.y + rect1.height > rect2.y;
    }
}

export default Catapult;
