/**
 * PhysicsEngine.js
 * Helper for physics simulation, collision detection, and movement
 * Handles Mario physics, enemy physics, particles, and camera
 */

export class PhysicsEngine {
    /**
     * Update Mario movement based on key inputs
     * @param {Object} mario - Mario object
     * @param {Object} keys - Key states object
     * @param {Object} config - Game config with moveSpeed and jumpForce
     * @param {boolean} isCelebrating - If true, disable movement
     * @param {Function} playSound - Sound callback for jump
     */
    static updateMarioMovement(mario, keys, config, isCelebrating, playSound) {
        // Don't update movement during celebration
        if (isCelebrating) return;

        // Horizontal movement
        if (keys['ArrowLeft'] || keys['KeyA']) {
            mario.velocityX = -config.moveSpeed;
            mario.facing = 'left';
        } else if (keys['ArrowRight'] || keys['KeyD']) {
            mario.velocityX = config.moveSpeed;
            mario.facing = 'right';
        } else {
            mario.velocityX *= 0.8; // Friction
        }

        // Jumping
        if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && mario.onGround) {
            mario.velocityY = config.jumpForce;
            mario.onGround = false;
            if (playSound) playSound('jump');
        }
    }

    /**
     * Update Mario physics (gravity and position)
     * @param {Object} mario - Mario object
     * @param {Object} config - Game config with gravity
     * @param {Object} level - Current level data
     * @param {boolean} levelCompleted - If level is completed
     * @param {Function} onFallOff - Callback when Mario falls off world
     */
    static updateMarioPhysics(mario, config, level, levelCompleted, onFallOff) {
        // Apply gravity
        mario.velocityY += config.gravity;

        // Update position
        mario.x += mario.velocityX;
        mario.y += mario.velocityY;

        // Prevent going off left edge
        if (mario.x < 0) {
            mario.x = 0;
        }

        // Stop Mario at finish line during celebration
        if (mario.x > level.endX && levelCompleted) {
            mario.x = level.endX;
            mario.velocityX = 0;
        }

        // Check if Mario fell off the world
        if (mario.y > config.canvasHeight + 100) {
            if (onFallOff) onFallOff();
        }
    }

    /**
     * Update enemy movement and AI
     * @param {Array} enemies - Array of enemies
     * @param {Array} walls - Array of walls
     * @param {Array} platforms - Array of platforms
     * @param {number} levelWidth - Level width
     * @param {boolean} isCelebrating - If true, disable updates
     */
    static updateEnemies(enemies, walls, platforms, levelWidth, isCelebrating) {
        // Don't update enemies during celebration
        if (isCelebrating) return;

        enemies.forEach(enemy => {
            // Store old position for collision detection
            const oldX = enemy.x;
            enemy.x += enemy.velocityX;

            // Check wall collisions
            const hitWall = walls.some(wall => {
                return enemy.x < wall.x + wall.width &&
                       enemy.x + enemy.width > wall.x &&
                       enemy.y < wall.y + wall.height &&
                       enemy.y + enemy.height > wall.y;
            });

            if (hitWall) {
                // Reverse position and direction
                enemy.x = oldX;
                enemy.velocityX *= -1;
                console.log(`🧱 Enemy hit wall, reversing direction`);
            }

            // Simple AI: reverse direction at platform edges
            const platform = platforms.find(p =>
                enemy.x >= p.x - 10 && enemy.x <= p.x + p.width + 10 &&
                enemy.y >= p.y - enemy.height - 5 && enemy.y <= p.y + 5
            );

            if (!platform || enemy.x <= 0 || enemy.x >= levelWidth) {
                enemy.velocityX *= -1;
            }
        });
    }

    /**
     * Check all collisions (platforms, walls, enemies, etc.)
     * @param {Object} mario - Mario object
     * @param {Object} gameState - All game entities
     * @param {Object} callbacks - Callbacks for various collision events
     */
    static checkCollisions(mario, gameState, callbacks) {
        const {
            platforms, questionBlocks, enemies, walls, catapults,
            piranhaPlants, boulders, flyingEyes
        } = gameState;

        const {
            onQuestionBlock, onEnemyDefeat, onMarioDeath, onAddParticles
        } = callbacks;

        // Platform collisions
        mario.onGround = false;

        platforms.forEach(platform => {
            if (this.isColliding(mario, platform)) {
                // Check if Mario is landing on top
                if (mario.velocityY > 0 && mario.y + mario.height - mario.velocityY <= platform.y + 5) {
                    mario.y = platform.y - mario.height;
                    mario.velocityY = 0;
                    mario.onGround = true;
                }
                // Hit from below
                else if (mario.velocityY < 0 && mario.y - mario.velocityY >= platform.y + platform.height - 5) {
                    mario.y = platform.y + platform.height;
                    mario.velocityY = 0;
                }
                // Side collision
                else {
                    if (mario.velocityX > 0) {
                        mario.x = platform.x - mario.width;
                    } else if (mario.velocityX < 0) {
                        mario.x = platform.x + platform.width;
                    }
                    mario.velocityX = 0;
                }
            }
        });

        // Boulder collisions (grounded boulders act as solid platforms)
        boulders.forEach(boulder => {
            if (boulder.hasLanded && this.isColliding(mario, boulder)) {
                // Determine collision direction based on overlap
                const overlapLeft = (mario.x + mario.width) - boulder.x;
                const overlapRight = (boulder.x + boulder.width) - mario.x;
                const overlapTop = (mario.y + mario.height) - boulder.y;
                const overlapBottom = (boulder.y + boulder.height) - mario.y;

                // Find the smallest overlap to determine collision side
                const minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);

                if (minOverlap === overlapTop && mario.velocityY > 0) {
                    // Landing on top of boulder
                    mario.y = boulder.y - mario.height;
                    mario.velocityY = 0;
                    mario.onGround = true;
                } else if (minOverlap === overlapBottom && mario.velocityY < 0) {
                    // Hitting boulder from below
                    mario.y = boulder.y + boulder.height;
                    mario.velocityY = 0;
                } else if (minOverlap === overlapLeft && mario.velocityX > 0) {
                    // Hitting boulder from left
                    mario.x = boulder.x - mario.width;
                    mario.velocityX = 0;
                } else if (minOverlap === overlapRight && mario.velocityX < 0) {
                    // Hitting boulder from right
                    mario.x = boulder.x + boulder.width;
                    mario.velocityX = 0;
                }
            }
        });

        // Question block collisions (non-blocking - just trigger on contact)
        questionBlocks.forEach(block => {
            if (!block.hit && this.isColliding(mario, block)) {
                // Trigger question block on any contact (pass-through)
                if (onQuestionBlock) onQuestionBlock(block);
            }
        });

        // Wall collisions
        walls.forEach(wall => {
            if (this.isColliding(mario, wall)) {
                // Determine collision direction based on previous position
                const overlapLeft = (mario.x + mario.width) - wall.x;
                const overlapRight = (wall.x + wall.width) - mario.x;
                const overlapTop = (mario.y + mario.height) - wall.y;
                const overlapBottom = (wall.y + wall.height) - mario.y;

                // Find the smallest overlap to determine collision side
                const minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);

                if (minOverlap === overlapTop && mario.velocityY > 0) {
                    // Landing on top of wall
                    mario.y = wall.y - mario.height;
                    mario.velocityY = 0;
                    mario.onGround = true;
                } else if (minOverlap === overlapBottom && mario.velocityY < 0) {
                    // Hit wall from below
                    mario.y = wall.y + wall.height;
                    mario.velocityY = 0;
                } else if (minOverlap === overlapLeft && mario.velocityX > 0) {
                    // Hit wall from left side
                    mario.x = wall.x - mario.width;
                    mario.velocityX = 0;
                } else if (minOverlap === overlapRight && mario.velocityX < 0) {
                    // Hit wall from right side
                    mario.x = wall.x + wall.width;
                    mario.velocityX = 0;
                }
            }
        });

        // Catapult collisions (solid obstacles)
        catapults.forEach(catapult => {
            if (this.isColliding(mario, catapult)) {
                // Treat catapults as solid platforms
                if (mario.velocityY > 0) {
                    mario.y = catapult.y - mario.height;
                    mario.velocityY = 0;
                    mario.onGround = true;
                }
            }
        });

        // Enemy collisions
        enemies.forEach((enemy, index) => {
            if (this.isColliding(mario, enemy)) {
                // Check if Mario jumped on enemy
                if (mario.velocityY > 0 && mario.y < enemy.y + enemy.height / 2) {
                    // Bounce on enemy
                    mario.velocityY = -8; // Bounce

                    // Only defeat enemy if it doesn't have a helmet
                    if (!enemy.hasHelmet) {
                        if (onEnemyDefeat) onEnemyDefeat(index);
                        if (onAddParticles) onAddParticles(enemy.x, enemy.y, '#FFD700');
                        console.log(`👾 Mario defeated enemy`);
                    } else {
                        // Helmet enemy - just bounce, don't defeat
                        if (onAddParticles) onAddParticles(enemy.x, enemy.y, '#4169E1');
                        console.log(`🛡️ Mario bounced on helmet enemy (not defeated)`);
                    }
                } else {
                    // Mario hit by enemy
                    console.log(`👾 Mario hit by enemy - restarting level`);
                    if (onMarioDeath) onMarioDeath();
                }
            }
        });

        // Piranha Plant collisions
        piranhaPlants.forEach(plant => {
            if (!plant.flattened && this.isColliding(mario, plant)) {
                // Check if Mario jumped on plant
                if (mario.velocityY > 0 && mario.y < plant.y + plant.height / 2) {
                    // Plant flattened
                    plant.flattened = true;
                    plant.flattenedTimer = 120; // Flattened for 2 seconds
                    mario.velocityY = -8; // Bounce
                    if (onAddParticles) onAddParticles(plant.x, plant.y, '#228B22');
                    console.log(`🌸 Mario flattened piranha plant`);
                } else {
                    // Mario hit by plant
                    console.log(`🌸 Mario hit by piranha plant - restarting level`);
                    if (onMarioDeath) onMarioDeath();
                }
            }

            // Check if stepping on flattened plant (acts as platform)
            if (plant.flattened && this.isColliding(mario, plant)) {
                // Mario lands on top of flattened plant
                if (mario.velocityY > 0 && mario.y < plant.y + plant.height / 2) {
                    mario.y = plant.y - mario.height;
                    mario.velocityY = 0;
                    mario.onGround = true;
                }
            }
        });

        // Flying Eye collisions
        if (flyingEyes) {
            flyingEyes.forEach((eye, index) => {
                // Eye position is CENTER, convert to top-left corner for collision
                const eyeLeft = eye.x - eye.width / 2;
                const eyeTop = eye.y - eye.height / 2;
                const eyeRect = {
                    x: eyeLeft,
                    y: eyeTop,
                    width: eye.width,
                    height: eye.height
                };

                if (this.isColliding(mario, eyeRect)) {
                    // Check if Mario jumped on eye from above
                    if (mario.velocityY > 0 && mario.y < eyeTop + eye.height / 2) {
                        // Eye defeated
                        mario.velocityY = -8; // Bounce
                        flyingEyes.splice(index, 1); // Remove eye
                        if (onAddParticles) onAddParticles(eye.x, eye.y, '#DC143C');
                        console.log(`👁️ Mario defeated flying eye`);
                    } else {
                        // Mario hit by eye
                        console.log(`👁️ Mario hit by flying eye - restarting level`);
                        if (onMarioDeath) onMarioDeath();
                    }
                }
            });
        }
    }

    /**
     * Rectangle-Rectangle collision detection
     * @param {Object} rect1 - First rectangle
     * @param {Object} rect2 - Second rectangle
     * @returns {boolean} - True if colliding
     */
    static isColliding(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;
    }

    /**
     * Update camera to follow Mario
     * @param {Object} camera - Camera object with x, y
     * @param {Object} mario - Mario object
     * @param {number} canvasWidth - Canvas width
     */
    static updateCamera(camera, mario, canvasWidth) {
        // Camera follows Mario horizontally, centered
        camera.x = mario.x - canvasWidth / 2 + mario.width / 2;
        camera.y = 0; // Fixed vertical camera
    }

    /**
     * Create particle effects
     * @param {number} x - X position
     * @param {number} y - Y position
     * @param {string} color - Particle color
     * @param {Array} particles - Particles array to add to
     * @param {number} count - Number of particles to create
     */
    static addParticles(x, y, color, particles, count = 10) {
        for (let i = 0; i < count; i++) {
            particles.push({
                x: x,
                y: y,
                velocityX: (Math.random() - 0.5) * 8,
                velocityY: (Math.random() - 0.5) * 8,
                life: 1.0,
                decay: 0.02,
                size: 4,
                color: color
            });
        }
    }

    /**
     * Create small particle burst
     * @param {number} x - X position
     * @param {number} y - Y position
     * @param {string} color - Particle color
     * @param {Array} particles - Particles array to add to
     */
    static addSmallParticles(x, y, color, particles) {
        this.addParticles(x, y, color, particles, 5);
    }

    /**
     * Update all particles
     * @param {Array} particles - Array of particles
     * @returns {Array} - Updated particles array (with dead particles removed)
     */
    static updateParticles(particles) {
        const updatedParticles = [];

        particles.forEach(particle => {
            particle.x += particle.velocityX;
            particle.y += particle.velocityY;
            particle.velocityY += 0.3; // Gravity
            particle.life -= particle.decay;

            if (particle.life > 0) {
                updatedParticles.push(particle);
            }
        });

        return updatedParticles;
    }
}

export default PhysicsEngine;
