import { WAVE_CONFIG } from './waveConfig.js'
import { Enemies } from './enemies.js'

export class WaveManager {

    constructor(scene, level, wave) {
        this.scene = scene;
        this.level = level;
        this.wave = wave-1;
        this.schedule = 0;
        this.scheduleInfo = null;
        this.spawnX = WAVE_CONFIG[this.level].spawnX;
        this.spawnY = WAVE_CONFIG[this.level].spawnY;
        this.endX = WAVE_CONFIG[this.level].endX;
        this.endY = WAVE_CONFIG[this.level].endY;
        this.path = null;
        this.levelActive = true;
        this.waveActive = false;

        this.waveTimer = 0;
        this.placeCore();
    }

    waveScheduleStartTime() {
        this.schedule++;
        this.scheduleInfo = WAVE_CONFIG[this.level][this.wave][this.schedule]
        this.waveStart = this.scheduleInfo.begin * 1000;
    }

    nextWave() {
        // Next Wave will be started in the interfaceManager
        if (this.waveActive === true) {
            this.wave++; 
            this.waveTimer = 0;
            this.schedule = 0;
            this.waveScheduleStartTime();
        }
    }

    placeCore() {
        this.scene.add.sprite(this.scene.gridToLocation(this.endX), this.scene.gridToLocation(this.endY), 'towers', 8);
        const rotatingCore = this.scene.add.sprite(this.scene.gridToLocation(this.endX), this.scene.gridToLocation(this.endY), 'towers', 9);
        const glowingCore = this.scene.add.sprite(this.scene.gridToLocation(this.endX), this.scene.gridToLocation(this.endY), 'towers', 19).setAlpha(0);
        this.scene.tweens.add({
            targets: rotatingCore,
            duration: 5000,
            angle: 360,
            alpha: [0.5, 1, 0.5],
            repeat: -1,
            yoyo: false
        });
        this.scene.tweens.add({
            targets: glowingCore,
            duration: 5000,
            alpha: .4,
            scale: 2,
            repeat: -1,
            yoyo: true
        });
    }

    update(time, delta) {
        // Handle Enemy Pathing
        this.scene.enemies.children.iterate((enemy) => {
            const path = enemy.props.path;
            const pathPhase = enemy.props.pathPhase;
            const speed = enemy.props.speed;
            const offsetX = enemy.props.offsetX;
            const offsetY = enemy.props.offsetY;
            
            // Initialize distance tracking if not exists
            if (enemy.props.distanceTraveled === undefined) {
                enemy.props.distanceTraveled = 0;
            }
            
            // Only move if we have a valid path and pathPhase
            if (path && pathPhase !== undefined) {
                // Calculate movement for this frame
                const segmentSpeed = speed; // Normalize by delta time
                
                // Get current and next points in the path
                const currentPoint = path[pathPhase];
                const nextPoint = path[pathPhase + 1];
                
                if (currentPoint && nextPoint) {
                    // Calculate direction vector from current to next point
                    const dx = this.scene.gridToLocation(nextPoint.x, offsetX) - this.scene.gridToLocation(currentPoint.x, offsetX);
                    const dy = this.scene.gridToLocation(nextPoint.y, offsetY) - this.scene.gridToLocation(currentPoint.y, offsetY);
                    const distance = Math.sqrt(dx * dx + dy * dy);
                    
                    // Normalize the direction
                    if (distance > 0) {
                        const normalizedDx = dx / distance;
                        const normalizedDy = dy / distance;

                        const velocX = normalizedDx * segmentSpeed;
                        const velocY = normalizedDy * segmentSpeed;
                        
                        // Calculate actual movement this frame
                        const movementDistance = Math.sqrt(velocX * velocX + velocY * velocY) * (delta / 1000);
                        enemy.props.distanceTraveled += movementDistance;
                        
                        // Move towards next point
                        enemy.body.setVelocity(velocX, velocY);

                        if (Math.abs(velocY) > Math.abs(velocX)) {
                            if (velocY > 0) {
                                enemy.play(`${enemy.props.type}-down`, true);
                            } else {
                                enemy.play(`${enemy.props.type}-up`, true);
                            }
                        } else {
                            if (velocX > 0) {
                                enemy.play(`${enemy.props.type}-side`, true);
                                enemy.setFlipX(true);
                            } else {
                                enemy.play(`${enemy.props.type}-side`, true);
                                enemy.setFlipX(false);
                            }
                        }
                        
                        // Check if we've reached the next point
                        const distToNextPoint = Math.sqrt(
                            Math.pow(enemy.x - this.scene.gridToLocation(nextPoint.x, offsetX), 2) + 
                            Math.pow(enemy.y - this.scene.gridToLocation(nextPoint.y, offsetY), 2)
                        );
                        
                        if (distToNextPoint < segmentSpeed * 0.5) { // Threshold for reaching point
                            enemy.props.pathPhase++; // Move to next path segment
                            
                            // If we've reached the end of the path, remove the enemy or handle accordingly
                            if (enemy.props.pathPhase >= path.length - 1) {
                                // Enemy reached destination - you might want to handle this differently
                                enemy.body.setVelocity(0, 0);
                                // Remove enemy from scene or mark for removal
                            }
                        }
                    } else {
                        // We're at the last point in the path
                        enemy.body.setVelocity(0, 0);
                    }
                } else if (currentPoint && !nextPoint) {
                    // Last point in path - stop moving
                    enemy.body.setVelocity(0, 0);
                }
            }
        });
        
        // Handle Waves and Schedules
        this.waveTimer += delta;

        if (this.waveTimer >= this.waveStart && this.levelActive === true && this.waveActive===true) {            
            //console.log('Wave',this.wave,'Schedule',this.schedule);
            // Make path synchronous
            this.makePath().then(() => {
                // Spawn enemies after path is ready
                this.spawnSchedule();
                
                if (WAVE_CONFIG[this.level][this.wave].hasOwnProperty(this.schedule + 1)) {
                    this.waveScheduleStartTime();
                } else if (WAVE_CONFIG[this.level].hasOwnProperty(this.wave+1)) {
                    this.waveActive = false;
                    this.scene.UIScene.interfaceManager.showNextWave();
                    //this.nextWave();
                } else {
                    console.log('LEVEL COMPLETE');
                    this.levelActive = false;
                }
            });
        }
    }

    spawnSchedule() {
        for (let i = 1; i <= 10; i++) {
            // Basic Enemies
            if (this.scheduleInfo.hasOwnProperty(`basic${i}`)) {
                let type = `basic${i}`;
                for (let e = 0; e < this.scheduleInfo[type]; e++) {
                    const enemy = new Enemies(this.scene, type, this.spawnX, this.spawnY, this.path);
                }
            }
        }
    }

    makePath() {
        return new Promise((resolve) => {
            this.easyStar = new EasyStar.js();
            
            // Set up the grid for pathfinding
            const width = this.scene.levelMap.width;
            const height = this.scene.levelMap.height;
            const grid = [];
            
            // Create a grid based on collision data
            for (let y = 0; y < height; y++) {
                grid[y] = [];
                for (let x = 0; x < width; x++) {
                    // Check if the tile at this position is colliding
                    const tile = this.scene.mainLayer.getTileAt(x, y);
                    if (tile && tile.properties.collides) {
                        grid[y][x] = 1; // Blocked
                    } else {
                        grid[y][x] = 0; // Free space
                    }
                }
            }
            this.easyStar.setGrid(grid);
            
            this.easyStar.setAcceptableTiles([0]); // Only allow movement on tiles with value 0
            
            this.easyStar.findPath(
                this.spawnX, 
                this.spawnY,
                this.endX,
                this.endY,
                (path) => {
                    if (path === null) {
                        console.log("No path found");
                        this.path = null;
                    } else {
                        this.path = path;
                    }
                    resolve();
                }
            );
            
            this.easyStar.calculate();
        });
    }

}