import { LEVEL_CONFIG } from './config.js';

export class GameScene extends Phaser.Scene {
    constructor() {
        super({ key: 'GameScene' });

        this.gridConfig = {
            allPadding: 50,
            leftPadding: 700,
            rows: 8,
            cols: 8,
            jewelWidth: 100,
            jewelHeight: 100,
        };

        // Stats
        this.numberOfJewels = 4;
        this.startRows = 3;
        this.level = 1;
        this.matchesNeeded = 10;
        this.score = 0;
        this.ally = 'goblin';

        // Status Indication
        this.isDropping = false;
        this.isSwapping = false;
        this.isDestroying = false;
        this.isMovingUp = false;
        this.isPlayingVideo = false;
        
        // Add selectedJewel property
        this.selectedJewel = null;
        this.swapWithJewel = null;

        // Timer properties
        this.moveTimer = 0;
        this.moveInterval = 12000;
        this.timerText = null;
    }

    preload() {
        // Jewels
        this.load.spritesheet('jewels', 'assets/jewels.png', {
            frameWidth: 100,
            frameHeight: 100
        });
        
        // Fonts
        this.load.font('cruiser', 'assets/NEUROPOL.ttf');
        this.load.font('code', 'assets/CodePredators-Regular.otf');

        // Music
        this.load.audio('goblin-music', 'assets/goblin-music.mp3');
        this.load.audio('beach-music', 'assets/beach-music.mp3');
        this.load.audio('clear', 'assets/clear.mp3');
        this.load.audio('level-up', 'assets/level-up.mp3');
        this.load.audio('switch', 'assets/switch.mp3');

        // Ally Videos
        this.load.video('goblin-resting', 'assets/goblin-resting.mp4');
        this.load.video('goblin-excited', 'assets/goblin-excited.mp4');
        this.load.video('goblin-pleased', 'assets/goblin-pleased.mp4');
        this.load.video('goblin-match', 'assets/goblin-match.mp4');
    }

    create() {
        this.makeGrid();
        this.physics.world.setBounds(this.grid.getBounds().x - 50, this.grid.getBounds().y - 50, this.grid.getBounds().width + 100, this.grid.getBounds().height + 100);
        this.jewels = this.physics.add.group({
            collideWorldBounds: true,
        });
        this.physics.add.collider(this.jewels, this.jewels);
        this.createStart();

        // Background Music
        this.bgMusic = this.sound.add('goblin-music', { volume: 0.5 });
        this.bgMusic.loop = true;
        this.bgMusic.play();

        // Create the score text
        this.scoreText = this.add.text(20, 50, 'Score: 0', {
            fontFamily: 'cruiser, arial',
            fontSize: '36px',
            fill: '#ffffff',
            padding: {
                left: 10,
                right: 10,
                top: 5,
                bottom: 5
            }
        }).setOrigin(0);

        // Create the Level text
        this.LevelText = this.add.text(20, 116, `Level: ${this.level}`, {
            fontFamily: 'cruiser, arial',
            fontSize: '36px',
            fill: '#ffffff',
            padding: {
                left: 10,
                right: 10,
                top: 5,
                bottom: 5
            }
        }).setOrigin(0);

        // Create the timer text
        this.timerText = this.add.text(20, 182, 'Next Row:', {
            fontFamily: 'cruiser, arial',
            fontSize: '36px',
            fill: '#ffffff',
            padding: {
                left: 10,
                right: 10,
                top: 5,
                bottom: 5
            }
        }).setOrigin(0);

        // Create the Matches Needed text
        this.matchesText = this.add.text(20, 248, `Remaining Matches: ${this.matchesNeeded}`, {
            fontFamily: 'cruiser, arial',
            fontSize: '36px',
            fill: '#ffffff',
            padding: {
                left: 10,
                right: 10,
                top: 5,
                bottom: 5
            }
        }).setOrigin(0);

        this.allyVideo = this.add.video(350, 610, `${this.ally}-resting`).setOrigin(0.5);
        this.allyVideo.play(true);
    }

    update(time, delta) {
        // Update the move timer
        this.moveTimer += delta;
        
        // Check if it's time to move all jewels up
        if (this.moveTimer >= this.moveInterval && this.isDropping === false && this.isSwapping === false && this.isDestroying === false) {
            this.moveAllJewelsUp();
            this.moveTimer = 0; // Reset the timer
        }
        
        // Update the timer display
        const timeRemaining = (this.moveInterval - this.moveTimer) / 1000;
        const displayTime = timeRemaining.toFixed(2);
        if (this.timerText) {
            this.timerText.setText(`Next Row: ${displayTime}`);
        }
    }

    makeGrid() {
        this.grid = this.add.rectangle(
            this.gridConfig.leftPadding + this.gridConfig.allPadding, 
            0 + this.gridConfig.allPadding, 
            this.gridConfig.cols * this.gridConfig.jewelWidth, 
            this.gridConfig.rows*this.gridConfig.jewelHeight, 
            0x000000,
            .5
        ).setOrigin(0);
    }

    createJewel(type, col, row) {
        // Create a jewel sprite from the spritesheet using the type as frame index
        const jewel = this.physics.add.sprite(
            col * this.gridConfig.jewelWidth + this.gridConfig.leftPadding, 
            row * this.gridConfig.jewelHeight, 
            'jewels', 
            type
        );
        jewel.setOrigin(0.5);
        jewel.setDisplaySize(this.gridConfig.jewelWidth, this.gridConfig.jewelHeight);
        jewel.jewelType = type;
        this.jewels.add(jewel);
        
        // Add click event to the jewel
        jewel.setInteractive();
        jewel.on('pointerdown', () => {
            this.handleJewelClick(jewel.x, jewel.y);
        });
        
        return jewel;
    }

    createStart() {
        // Create jewels at the bottom of the grid
        let createWait = 0;
        const startRow = this.gridConfig.rows - this.startRows;
        
        for (let row = this.startRows; row > 0; row--) {
            for (let col = 1; col <= this.gridConfig.cols; col++) {
                let type = null;
                let match = false;

                do {
                    type = Phaser.Math.Between(0, this.numberOfJewels - 1)
                    match = false; 

                    if (this.getJewelAtPosition(col-1, startRow + row) === type && 
                    this.getJewelAtPosition(col-2, startRow + row) === type) {
                        match = true;
                    }

                    if (this.getJewelAtPosition(col, startRow + row + 1) === type &&
                    this.getJewelAtPosition(col, startRow + row + 2) === type) {
                        match = true;
                    }
                } while (match === true);
                
                // Create the jewel at the correct position
                this.createJewel(type, col, startRow + row);
            }
        }
    }

    getJewelAtPosition(col, row) {
        // Convert grid coordinates to world coordinates
        const x = col * this.gridConfig.jewelWidth + this.gridConfig.leftPadding;
        const y = row * this.gridConfig.jewelHeight;
        
        // Find the jewel at that position
        let jewelAtPosition = null;
        
        // Iterate through all jewels to find one near the specified position
        this.jewels.children.iterate((jewel) => {
            if (jewel && 
                Math.abs(jewel.x - x) < this.gridConfig.jewelWidth / 2 &&
                Math.abs(jewel.y - y) < this.gridConfig.jewelHeight / 2) {
                jewelAtPosition = jewel;
                return false; // Stop iteration
            }
        });
        
        // Return the jewel type or null if not found
        return jewelAtPosition ? jewelAtPosition.jewelType : null;
    }
    
    // New function to handle jewel clicks
    handleJewelClick(x, y) {
        // Find which jewel was clicked
        const clickedJewel = this.getJewelAtWorldPosition(x, y);
        
        if (!clickedJewel || this.isSwapping) {
            return;
        }
        
        // If no jewel is currently selected
        if (!this.selectedJewel) {
            this.selectJewel(clickedJewel);
            return;
        }
        
        // If clicking on the already selected jewel, deselect it
        if (clickedJewel === this.selectedJewel) {
            this.deselectJewel();
            return;
        }
        
        // Check if clicked jewel is adjacent to selected jewel
        const isAdjacent = this.isAdjacent(this.selectedJewel, clickedJewel);
        
        if (isAdjacent) {
            // Mark for swap
            this.selectJewelForSwap(clickedJewel);
        } else {
            // Deselect current and select new jewel
            this.deselectJewel();
            this.selectJewel(clickedJewel);
        }
    }
    
    // Helper function to get jewel at world position
    getJewelAtWorldPosition(x, y) {
        let closestJewel = null;
        let minDistance = Infinity;
        
        this.jewels.children.iterate((jewel) => {
            if (jewel) {
                const distance = Phaser.Math.Distance.Between(jewel.x, jewel.y, x, y);
                if (distance < minDistance && distance < 50) { // 50 is half of jewel width/height
                    minDistance = distance;
                    closestJewel = jewel;
                }
            }
        });
        
        return closestJewel;
    }
    
    // Helper function to check if two jewels are adjacent (horizontally or vertically)
    isAdjacent(jewel1, jewel2) {
        const col1 = Math.floor((jewel1.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth);
        const row1 = Math.floor(jewel1.y / this.gridConfig.jewelHeight);
        
        const col2 = Math.floor((jewel2.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth);
        const row2 = Math.floor(jewel2.y / this.gridConfig.jewelHeight);
        
        // Check if jewels are adjacent (same row and adjacent columns, or same column and adjacent rows)
        return (row1 === row2 && Math.abs(col1 - col2) === 1) || (col1 === col2 && Math.abs(row1 - row2) === 1);
    }
    
    // Helper function to select a jewel for swap
    selectJewelForSwap(jewel) {
        this.swapWithJewel = jewel;
        this.tweens.add({
            targets: this.selectedJewel,
            scale: 1,
            duration: 200
        });
        this.swapJewel();
    }

    // Helper function to select a jewel for swap
    selectJewel(jewel) {
        this.selectedJewel = jewel;
        this.tweens.add({
            targets: jewel,
            scale: 1.2,
            duration: 200
        });
    }
    
    // Helper function to deselect a jewel
    deselectJewel() {
        if (this.selectedJewel) {
            this.tweens.add({
                targets: this.selectedJewel,
                scale: 1,
                duration: 200
            });
            this.selectedJewel = null;
        }
    }

    // Modified swap function to disable clicks during execution
    swapJewel() {
        if (this.isMovingUp === true) {
            this.time.delayedCall(300, ()=> {
                this.swapJewel();
            })
            return;
        }
        // Set swapping flag to prevent new clicks from being processed
        this.isSwapping = true;
        this.sound.play('switch');
        
        // Disable all jewel interactivity temporarily 
        this.jewels.children.iterate((jewel) => {
            if (jewel) {
                jewel.disableInteractive();
            }
        });
        
        // Perform the swap animation here - currently empty
        const fromX = this.selectedJewel.x;
        const fromY = this.selectedJewel.y;
        const toX = this.swapWithJewel.x;
        const toY = this.swapWithJewel.y;
        this.tweens.add({
            targets: this.selectedJewel,
            x: toX,
            y: toY,
            duration: 300
        });
        this.tweens.add({
            targets: this.swapWithJewel,
            x: fromX,
            y: fromY,
            duration: 300,
            onComplete: () => {
                this.checkMatches();
            }
        });
        this.selectedJewel = null;
        this.swapWithJewel = null;
        

        // After swap completes, re-enable interactivity and reset flag
        this.time.delayedCall(300, () => { // Adjust delay as needed for animation duration
            this.jewels.children.iterate((jewel) => {
                if (jewel) {
                    jewel.setInteractive();
                }
            });
            
            this.isSwapping = false;
        });
    }

    reduceMatches(amount) {
        this.matchesNeeded -= amount;
        if (this.matchesNeeded <= 0) {
            this.levelUp();
        }
        this.matchesText.setText(`Matches Needed: ${this.matchesNeeded}`);
    }

    levelUp() {
        this.level ++;
        const newLevel = LEVEL_CONFIG[this.level];
        this.numberOfJewels = newLevel.numberOfJewels;
        this.matchesNeeded = newLevel.matchesNeeded;
        this.moveInterval = newLevel.moveInterval;
        this.LevelText.setText(`Level: ${this.level}`);
        this.sound.play('level-up');

        // Create the New Level text
        const newLevelText = this.add.text(1150, 250, `Level ${this.level}`, {
            fontFamily: 'code, arial',
            fontSize: '100px',
            fill: '#ea00ffff',
            padding: {
                left: 10,
                right: 10,
                top: 5,
                bottom: 5
            }
        }).setOrigin(0.5);

        // Add cool eye-catching effect
        this.tweens.add({
            targets: newLevelText,
            scale: { from: 0.5, to: 1.5 },
            alpha: { from: 0, to: 1 },
            duration: 1000,
            ease: 'Back.easeOut',
            yoyo: true
        });

        // Fade out and destroy after 500ms
        this.time.delayedCall(1200, () => {
            this.tweens.add({
                targets: newLevelText,
                angle: 360,
                scale: 0,
                alpha: 0,
                duration: 500,
                onComplete: () => {
                    newLevelText.destroy();
                }
            });
        });
    }

    // Function to check for matches and destroy them
    checkMatches() {
        const matchedJewels = new Set();
        
        // Check horizontal matches
        for (let row = 1; row <= this.gridConfig.rows; row++) {
            let count = 1;
            let currentType = this.getJewelAtPosition(1, row);
            
            for (let col = 2; col <= this.gridConfig.cols; col++) {
                const jewelType = this.getJewelAtPosition(col, row);
                
                if (jewelType === currentType && jewelType !== null) {
                    count++;
                } else {
                    if (count >= 3) {
                        this.reduceMatches(1);
                        // Add all jewels in this match to the matched set
                        for (let i = col - count; i < col; i++) {
                            const key = `${i},${row}`;
                            matchedJewels.add(key);
                        }
                    }
                    count = 1;
                    currentType = jewelType;
                }
            }
            
            // Check for match at the end of row
            if (count >= 3) {
                this.reduceMatches(1);
                for (let i = this.gridConfig.cols - count + 1; i <= this.gridConfig.cols; i++) {
                    const key = `${i},${row}`;
                    matchedJewels.add(key);
                }
            }
        }
        
        // Check vertical matches
        for (let col = 1; col <= this.gridConfig.cols; col++) {
            let count = 1;
            let currentType = this.getJewelAtPosition(col, 0);
            
            for (let row = 1; row <= this.gridConfig.rows; row++) {
                const jewelType = this.getJewelAtPosition(col, row);
                
                if (jewelType === currentType && jewelType !== null) {
                    count++;
                } else {
                    if (count >= 3) {
                        this.reduceMatches(1);
                        // Add all jewels in this match to the matched set
                        for (let i = row - count; i < row; i++) {
                            const key = `${col},${i}`;
                            matchedJewels.add(key);
                        }
                    }
                    count = 1;
                    currentType = jewelType;
                }
            }
            
            // Check for match at the end of column
            if (count >= 3) {
                this.reduceMatches(1);
                for (let i = this.gridConfig.rows - count + 1; i <= this.gridConfig.rows; i++) {
                    const key = `${col},${i}`;
                    matchedJewels.add(key);
                }
            }
        }
        
        // If we found matches, destroy them and play video
        if (matchedJewels.size > 0) {
            this.playVideo(matchedJewels.size);
            const scoreMatches = matchedJewels.size / 3;
            const scoreAdd = Math.ceil(scoreMatches ** 2) * 10;
            this.score += scoreAdd;
            this.scoreText.setText(`Score: ${this.score}`);
            // ADD SCORE
            this.destroyMatchedJewels(matchedJewels);
            return true;
        }
        
        return false;
    }

    playVideo(amount) {
        if (this.isPlayingVideo === true) {
            return;
        }

        this.isPlayingVideo = true;
        let video = null;
        
        if (amount >= 5) {
            video = `${this.ally}-excited`;
        } else if (amount >= 4) {
            video = `${this.ally}-pleased`;
        } else {
            video = `${this.ally}-match`;
        }
        const showVideo = this.add.video(350, 610, video).setOrigin(0.5).setDepth(100);
        showVideo.play(false);
        this.time.delayedCall(5000, () => {
            this.isPlayingVideo = false;
            showVideo.destroy();
            console.log('end video');
        });
    }

    // Function to destroy matched jewels
    destroyMatchedJewels(matchedJewels) {
        if (this.isDestroying) {
            return;
        }

        this.isDestroying = true;
        // Create an array of jewels to destroy
        const jewelsToDestroy = [];
        
        this.jewels.children.iterate((jewel) => {
            if (jewel) {
                const col = Math.floor((jewel.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth);
                const row = Math.floor(jewel.y / this.gridConfig.jewelHeight);
                const key = `${col},${row}`;
                
                if (matchedJewels.has(key)) {
                    jewelsToDestroy.push(jewel);
                }
            }
        });
        
        this.sound.play('clear');

        // Animate destruction
        jewelsToDestroy.forEach((jewel) => {
            this.tweens.add({
                targets: jewel,
                scaleX: 0,
                scaleY: 0,
                alpha: 0,
                duration: 200,
                onComplete: () => {
                    jewel.destroy();
                    this.time.delayedCall(100, () => {
                        this.isDestroying = false;
                        this.dropJewels();
                    });                    
                }
            });
        });
    }

    dropJewels() {
        if (this.isDropping) {
            return;
        }

        this.isDropping = true;
        
        // Create a grid representation to track jewel positions
        const grid = [];
        for (let row = 1; row <= this.gridConfig.rows; row++) {
            grid[row] = [];
            for (let col = 1; col <= this.gridConfig.cols; col++) {
                grid[row][col] = null;
            }
        }
        
        // Populate the grid with jewel positions
        this.jewels.children.iterate((jewel) => {
            if (jewel) {
                const col = Math.floor((jewel.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth);
                const row = Math.floor(jewel.y / this.gridConfig.jewelHeight);
                
                // Ensure we're within grid bounds
                if (col >= 1 && col <= this.gridConfig.cols && row >= 1 && row <= this.gridConfig.rows) {
                    grid[row][col] = jewel;
                }
            }
        });
        
        // Find jewels that need to drop and their target positions
        const jewelsToDrop = [];
        
        for (let col = 1; col <= this.gridConfig.cols; col++) {
            let emptySpaces = 0;
            
            // Process from bottom to top
            for (let row = this.gridConfig.rows; row >= 1; row--) {
                if (grid[row][col] === null) {
                    emptySpaces++;
                } else if (emptySpaces > 0) {
                    // This jewel needs to drop
                    const jewel = grid[row][col];
                    const targetRow = row + emptySpaces;
                    
                    jewelsToDrop.push({
                        jewel: jewel,
                        fromRow: row,
                        toRow: targetRow
                    });
                    
                    // Update grid reference
                    grid[row][col] = null;
                    grid[targetRow][col] = jewel;
                }
            }
        }
        
        // If no jewels need to drop, we're done
        if (jewelsToDrop.length === 0) {
            this.isDropping = false;
            return;
        }
        
        // Animate the dropping
        let droppedCount = 0;
        
        jewelsToDrop.forEach((dropInfo) => {
            const { jewel, fromRow, toRow } = dropInfo;
            
            // Calculate target y position
            const targetY = toRow * this.gridConfig.jewelHeight;
            
            // Animate the jewel dropping
            this.tweens.add({
                targets: jewel,
                y: targetY,
                duration: 300,
                ease: 'Linear',
                onComplete: () => {
                    droppedCount++;
                    
                    // When all jewels have dropped, check for new matches
                    if (droppedCount === jewelsToDrop.length) {
                        this.time.delayedCall(100, () => {
                            this.isDropping = false;
                            // Check for new matches after dropping
                            this.checkMatches();
                        });
                    }
                }
            });
        });
    }

    // Function to move all jewels up one row
    moveAllJewelsUp() {
        this.isMovingUp = true;
        // Check if any jewel is at row 1 (topmost) that would go to row 0
        let gameOver = false;
        
        this.jewels.children.iterate((jewel) => {
            if (jewel) {
                const col = Math.floor((jewel.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth);
                const row = Math.floor(jewel.y / this.gridConfig.jewelHeight);
                
                // If jewel is at row 1 and would move up to row 0, game over
                if (row === 1 && col >= 1 && col <= this.gridConfig.cols) {
                    gameOver = true;
                }
            }
        });
        
        // If game over, end the game
        if (gameOver) {
            this.gameOver();
            return;
        }
        
        // Move all jewels up one row
        this.jewels.children.iterate((jewel) => {
            if (jewel) {
                const col = Math.floor((jewel.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth);
                const row = Math.floor(jewel.y / this.gridConfig.jewelHeight);
                
                // Only move jewels that are not at the top row
                if (row > 1 && col >= 1 && col <= this.gridConfig.cols) {
                    const targetRow = row - 1;
                    const targetY = targetRow * this.gridConfig.jewelHeight;
                    
                    // Animate the jewel moving up
                    this.tweens.add({
                        targets: jewel,
                        y: targetY,
                        duration: 300,
                        ease: 'Linear'
                    });
                }
            }
        });
        
        // Create new bottom row after moving all jewels up
        this.time.delayedCall(300, () => {
            this.isMovingUp = false;
            this.createBottomRow();
        });
    }

    // Function to create a new row of jewels at the bottom
    createBottomRow() {
        const newRow = 8;
        let jewelDelay = 0;
        
        for (let col = 1; col <= this.gridConfig.cols; col++) {
            let type = null;
            let match = false;

            do {
                type = Phaser.Math.Between(0, this.numberOfJewels - 1);
                match = false;

                // Check horizontal matches in the new row
                if (col >= 3) {
                    // Check if this would create a horizontal match of 3 or more
                    const leftType = this.getJewelAtPosition(col-1, newRow);
                    const leftLeftType = this.getJewelAtPosition(col-2, newRow);
                    
                    if (leftType === type && leftLeftType === type) {
                        match = true;
                    }
                }

                // Check vertical matches in the columns above
                if (newRow <= this.gridConfig.rows) {
                    const aboveType = this.getJewelAtPosition(col, newRow - 1);
                    
                    if (aboveType === type) {
                        // Check if there's a match of 3 or more by looking at additional positions
                        let count = 1;
                        
                        // Look up to see how many matching jewels we have in the column
                        for (let row = newRow - 2; row < this.gridConfig.rows; row++) {
                            const jewelType = this.getJewelAtPosition(col, row);
                            if (jewelType === type) {
                                count++;
                            } else {
                                break;
                            }
                        }
                        
                        // If we have 3 or more in a vertical line, it's a match
                        if (count >= 3) {
                            match = true;
                        }
                    }
                }

                // Also check for matches with jewels above the new row (if they exist)
                if (newRow < this.gridConfig.rows && col <= this.gridConfig.cols) {
                    const jewelAbove = this.getJewelAtPosition(col, newRow - 1);
                    
                    if (jewelAbove !== null) {
                        // Check horizontal match with jewels in the same row
                        let count = 0;
                        
                        // Look left to see how many matching jewels we have in that row
                        for (let c = col - 1; c >= 1; c--) {
                            const jewelType = this.getJewelAtPosition(c, newRow);
                            if (jewelType === type) {
                                count++;
                            } else {
                                break;
                            }
                        }
                        
                        // Look right to see how many matching jewels we have in that row
                        for (let c = col + 1; c <= this.gridConfig.cols; c++) {
                            const jewelType = this.getJewelAtPosition(c, newRow);
                            if (jewelType === type) {
                                count++;
                            } else {
                                break;
                            }
                        }
                        
                        // If we have at least 2 matching jewels in the row and one more above,
                        // or any other match scenario that creates a 3-in-a-row
                        if (count >= 2 && jewelAbove === type) {
                            match = true;
                        }
                    }
                }

            } while (match === true);
            
            // Create the jewel at the correct position
            this.createJewel(type, col, newRow);
        }
    }

    // Game over function
    gameOver() {
        console.log('Game Over!');
        // Add game over logic here (e.g., show game over screen, reset game, etc.)
        
        // For now, just restart the scene
        this.scene.restart();
    }
}