// 10 cols × 15 rows, 60 × 60 px tiles
// Playfield is 600 × 900 px, centered at x = 500..1100 in the 1600 × 900 canvas
const COLS = 10;
const ROWS = 15;
const TW = 60;
const TH = 60;
const OX = (1600 - COLS * TW) / 2; // left edge of maze = 500

const LAYOUT = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],  // 0  top wall
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],  // 1  open corridor
    [1, 0, 1, 1, 0, 0, 1, 1, 0, 1],  // 2  block rooms
    [1, 0, 1, 1, 0, 0, 1, 1, 0, 1],  // 3  (thick walls, same as row 2)
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],  // 4  open corridor
    [1, 0, 1, 0, 1, 1, 0, 1, 0, 1],  // 5  pre-ghost-house
    [1, 0, 1, 0, 0, 0, 0, 1, 0, 1],  // 6  ghost house (open centre)
    [1, 0, 1, 0, 1, 1, 0, 1, 0, 1],  // 7  post-ghost-house (mirror of 5)
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],  // 8  open corridor
    [1, 0, 1, 1, 0, 0, 1, 1, 0, 1],  // 9  block rooms (mirror of 2)
    [1, 0, 1, 1, 0, 0, 1, 1, 0, 1],  // 10 (mirror of 3)
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],  // 11 open corridor
    [1, 1, 0, 1, 0, 0, 1, 0, 1, 1],  // 12 narrow passage
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],  // 13 open corridor (player spawn)
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],  // 14 bottom wall
];

import { playMusic, stopMusic } from '../../audio.js';

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

    preload() {
        this.load.json('ddConfig', 'src/games/dot-dude/config.json');
        this.load.audio('ddMusic', 'assets/music/03-dot-dude.mp3');
        this.load.audio('ddPellet', 'assets/fx/pellet.mp3');
        this.load.audio('ddComplete', 'assets/fx/complete.mp3');
    }

    shutdown() {
        stopMusic(this);
    }

    init(data) {
        this.globalLives = data.lives;
        this.level = data.level || 1;
        this.gameActive = false;
    }

    create() {
        const all = this.cache.json.get('ddConfig');
        const lvl = String(this.level);
        this.cfg = all.levels ? (all.levels[lvl] ?? all.levels['1']) : all;

        this.dots = LAYOUT.map(row => row.map(cell => (cell === 0 ? 1 : 0)));
        this.totalDots = this.dots.flat().filter(d => d === 1).length;
        this.dotsEaten = 0;

        playMusic(this, 'ddMusic');

        this._initPlayer();
        this._initGhosts();

        // Background must be added first so it sits below all other layers
        this._drawBackground();
        this.mazeGfx = this.add.graphics();
        this.mainGfx = this.add.graphics();
        this.gameActive = true;
        this.mouthAngle = 0.4;
        this.mouthDir = -1;

        this._drawMaze();
        this._buildHUD();
        this._setupInput();
    }

    // ── helpers ─────────────────────────────────────────────────────────────

    _px(col) { return OX + (col + 0.5) * TW; }   // tile col → pixel x centre
    _py(row) { return (row + 0.5) * TH; }          // tile row → pixel y centre
    _col(px) { return Math.floor((px - OX) / TW); }
    _row(py) { return Math.floor(py / TH); }

    _wallAt(col, row) {
        if (col < 0 || col >= COLS || row < 0 || row >= ROWS) return true;
        return LAYOUT[row][col] === 1;
    }

    _canMoveTo(px, py, r) {
        return [
            [px - r + 1, py - r + 1],
            [px + r - 1, py - r + 1],
            [px - r + 1, py + r - 1],
            [px + r - 1, py + r - 1],
        ].every(([x, y]) => !this._wallAt(this._col(x), this._row(y)));
    }

    // ── init ─────────────────────────────────────────────────────────────────

    _initPlayer() {
        this.player = {
            x: this._px(4), y: this._py(13),
            dir: { dx: 0, dy: 0 },
            wantDir: { dx: 1, dy: 0 },
        };
    }

    _initGhosts() {
        const defs = [
            { col: 3, row: 6, dir: { dx: -1, dy: 0 }, color: 0xff4444 },
            { col: 5, row: 6, dir: { dx: 1, dy: 0 }, color: 0xff88ff },
            { col: 6, row: 6, dir: { dx: 1, dy: 0 }, color: 0x44ffff },
        ];
        this.ghosts = defs.map(g => ({
            x: this._px(g.col), y: this._py(g.row),
            targetX: this._px(g.col), targetY: this._py(g.row),
            dir: g.dir, color: g.color, active: false,
        }));
        this.cfg.ghostStartDelay.forEach((ms, i) => {
            this.time.delayedCall(ms, () => {
                if (!this.gameActive || !this.ghosts[i]) return;
                const ghost = this.ghosts[i];
                ghost.active = true;
                this._pickNextTarget(ghost);
            });
        });
    }

    _pickNextTarget(ghost) {
        const col = this._col(ghost.x);
        const row = this._row(ghost.y);
        const dir = this._chooseGhostDir(ghost, col, row, false);
        ghost.dir = dir;
        if (dir.dx !== 0 || dir.dy !== 0) {
            ghost.targetX = this._px(col + dir.dx);
            ghost.targetY = this._py(row + dir.dy);
        }
    }

    _buildHUD() {
        // Left panel
        this.add.text(250, 80, 'DOT DUDE', {
            fontSize: '30px', fontFamily: 'monospace', color: '#ffaa00',
        }).setOrigin(0.5).setDepth(10);

        this.livesText = this.add.text(250, 160, '♥ '.repeat(this.globalLives).trim(), {
            fontSize: '30px', fontFamily: 'monospace', color: '#ff4444',
        }).setOrigin(0.5).setDepth(10);

        // Right panel
        this.add.text(1350, 80, 'EAT', {
            fontSize: '26px', fontFamily: 'monospace', color: '#aaaaaa',
        }).setOrigin(0.5).setDepth(10);

        this.dotsText = this.add.text(1350, 140, `0 / ${this.cfg.pelletsToPass}`, {
            fontSize: '36px', fontFamily: 'monospace', color: '#ffff00',
        }).setOrigin(0.5).setDepth(10);
    }

    _setupInput() {
        this.cursors = this.input.keyboard.createCursorKeys();
    }

    // ── update ───────────────────────────────────────────────────────────────

    update(time, delta) {
        if (!this.gameActive) return;
        const dt = delta / 1000;

        // Input → buffer wantDir
        if (this.cursors.left.isDown) this.player.wantDir = { dx: -1, dy: 0 };
        else if (this.cursors.right.isDown) this.player.wantDir = { dx: 1, dy: 0 };
        else if (this.cursors.up.isDown) this.player.wantDir = { dx: 0, dy: -1 };
        else if (this.cursors.down.isDown) this.player.wantDir = { dx: 0, dy: 1 };

        this._movePlayer(dt);

        // Eat dot at current tile
        const col = this._col(this.player.x);
        const row = this._row(this.player.y);
        if (col >= 0 && col < COLS && row >= 0 && row < ROWS && this.dots[row][col] === 1) {
            this.dots[row][col] = 0;
            this.dotsEaten++;
            this.dotsText.setText(`${this.dotsEaten} / ${this.cfg.pelletsToPass}`);
            const snd = this.sound.add('ddPellet', { volume: 0.5 });
            snd.once('complete', () => snd.destroy());
            snd.play();
        }

        // Ghosts
        this.ghosts.forEach(g => this._updateGhost(g, dt));

        for (const g of this.ghosts) {
            if (g.active && Math.hypot(g.x - this.player.x, g.y - this.player.y) < 26) {
                this._endGame(false);
                return;
            }
        }

        if (this.dotsEaten >= this.cfg.pelletsToPass) { this._endGame(true); return; }

        // Mouth animation
        this.mouthAngle += this.mouthDir * 3 * dt;
        if (this.mouthAngle < 0.02) { this.mouthAngle = 0.02; this.mouthDir = 1; }
        if (this.mouthAngle > 0.45) { this.mouthAngle = 0.45; this.mouthDir = -1; }

        this._drawDynamic();
    }

    _movePlayer(dt) {
        const p = this.player;
        const move = this.cfg.playerSpeed * dt;

        // Tile the player's centre currently occupies
        const col = this._col(p.x);
        const row = this._row(p.y);
        const cx = this._px(col);
        const cy = this._py(row);

        // Allow a direction change from anywhere within the current tile (half-tile threshold).
        // This is forgiving: no pixel-perfect timing needed.
        const { dx: wdx, dy: wdy } = p.wantDir;
        if (Math.abs(p.x - cx) < TW / 2 && Math.abs(p.y - cy) < TH / 2) {
            if (!this._wallAt(col + wdx, row + wdy)) {
                p.dir = { dx: wdx, dy: wdy };
            }
        }

        const { dx, dy } = p.dir;

        if (dx !== 0) {
            // ── Horizontal movement ──────────────────────────────────────────
            // Hard-snap Y to the row's lane centre every frame.
            p.y = cy;

            const nx = p.x + dx * move;
            const nCol = this._col(nx);

            if (nCol !== col && this._wallAt(nCol, row)) {
                // About to enter a wall column: park at the near edge of the open tile.
                p.x = dx > 0 ? OX + (col + 1) * TW - 1 : OX + col * TW + 1;
                p.dir = { dx: 0, dy: 0 };
            } else {
                p.x = nx;
            }
        } else if (dy !== 0) {
            // ── Vertical movement ────────────────────────────────────────────
            // Hard-snap X to the column's lane centre every frame.
            p.x = cx;

            const ny = p.y + dy * move;
            const nRow = this._row(ny);

            if (nRow !== row && this._wallAt(col, nRow)) {
                p.y = dy > 0 ? (row + 1) * TH - 1 : row * TH + 1;
                p.dir = { dx: 0, dy: 0 };
            } else {
                p.y = ny;
            }
        } else {
            // Stopped: snap to tile centre so the turn threshold works correctly.
            p.x = cx;
            p.y = cy;
        }
    }

    _updateGhost(ghost, dt) {
        if (!ghost.active) return;
        const move = this.cfg.ghostSpeed * dt;

        const tdx = ghost.targetX - ghost.x;
        const tdy = ghost.targetY - ghost.y;
        const dist = Math.hypot(tdx, tdy);

        if (dist <= move) {
            // Arrived at the target tile centre: snap and choose next tile.
            ghost.x = ghost.targetX;
            ghost.y = ghost.targetY;
            this._pickNextTarget(ghost);
        } else {
            ghost.x += (tdx / dist) * move;
            ghost.y += (tdy / dist) * move;
        }
    }

    // allowReverse: true when the ghost is wall-blocked and needs an escape route.
    _chooseGhostDir(ghost, col, row, allowReverse) {
        const dirs = [{ dx: 1, dy: 0 }, { dx: -1, dy: 0 }, { dx: 0, dy: 1 }, { dx: 0, dy: -1 }];
        const rev = { dx: -ghost.dir.dx, dy: -ghost.dir.dy };
        const pc = this._col(this.player.x);
        const pr = this._row(this.player.y);

        let best = null, bestScore = Infinity;
        for (const d of dirs) {
            if (!allowReverse && d.dx === rev.dx && d.dy === rev.dy) continue;
            const nc = col + d.dx, nr = row + d.dy;
            if (this._wallAt(nc, nr)) continue;
            const score = Math.abs(nc - pc) + Math.abs(nr - pr);
            if (score < bestScore) { bestScore = score; best = d; }
        }
        // Last resort: try reverse even if not explicitly allowed
        if (!best && !this._wallAt(col + rev.dx, row + rev.dy)) best = rev;
        return best || { dx: 0, dy: 0 };
    }

    // ── drawing ──────────────────────────────────────────────────────────────

    _drawBackground() {
        const bg = this.add.graphics();
        // Full canvas
        bg.fillStyle(0x000011);
        bg.fillRect(0, 0, 1600, 900);
        // Side panels slightly lighter
        bg.fillStyle(0x08081a);
        bg.fillRect(0, 0, OX, 900);
        bg.fillRect(OX + COLS * TW, 0, OX, 900);
        // Subtle panel separators
        bg.lineStyle(1, 0x222244, 0.8);
        bg.lineBetween(OX, 0, OX, 900);
        bg.lineBetween(OX + COLS * TW, 0, OX + COLS * TW, 900);
    }

    _drawMaze() {
        const g = this.mazeGfx;
        g.fillStyle(0x000022);
        g.fillRect(OX, 0, COLS * TW, ROWS * TH);

        for (let r = 0; r < ROWS; r++) {
            for (let c = 0; c < COLS; c++) {
                if (LAYOUT[r][c] === 1) {
                    const x = OX + c * TW;
                    const y = r * TH;
                    g.fillStyle(0x0000cc);
                    g.fillRect(x + 1, y + 1, TW - 2, TH - 2);
                    g.lineStyle(2, 0x4455ff);
                    g.strokeRect(x + 3, y + 3, TW - 6, TH - 6);
                }
            }
        }
    }

    _drawDynamic() {
        const g = this.mainGfx;
        g.clear();

        // Dots
        for (let r = 0; r < ROWS; r++) {
            for (let c = 0; c < COLS; c++) {
                if (this.dots[r][c] === 1) {
                    g.fillStyle(0xffd700);
                    g.fillCircle(this._px(c), this._py(r), this.cfg.dotRadius);
                }
            }
        }

        // Ghosts
        this.ghosts.forEach(gh => { if (gh.active) this._drawGhost(g, gh.x, gh.y, gh.color); });

        // Player
        this._drawPlayer(g, this.player.x, this.player.y, this.player.dir, this.mouthAngle);
    }

    _drawPlayer(g, x, y, dir, mouthAngle) {
        const r = 18;
        g.fillStyle(0xffff00);
        g.fillCircle(x, y, r);
        const rot = Math.atan2(dir.dy, dir.dx);
        g.fillStyle(0x000022);
        g.fillTriangle(
            x, y,
            x + Math.cos(rot - mouthAngle) * (r + 2), y + Math.sin(rot - mouthAngle) * (r + 2),
            x + Math.cos(rot + mouthAngle) * (r + 2), y + Math.sin(rot + mouthAngle) * (r + 2)
        );
        g.fillStyle(0x000000);
        g.fillCircle(x + Math.cos(rot - 0.8) * 8, y + Math.sin(rot - 0.8) * 8, 3);
    }

    _drawGhost(g, x, y, color) {
        g.fillStyle(color);
        g.fillCircle(x, y - 6, 16);
        g.fillRect(x - 16, y - 6, 32, 20);
        g.fillTriangle(x - 16, y + 14, x - 8, y + 20, x, y + 14);
        g.fillTriangle(x, y + 14, x + 8, y + 20, x + 16, y + 14);
        g.fillStyle(0xffffff);
        g.fillCircle(x - 6, y - 8, 5);
        g.fillCircle(x + 6, y - 8, 5);
        g.fillStyle(0x0000cc);
        g.fillCircle(x - 5, y - 8, 2);
        g.fillCircle(x + 7, y - 8, 2);
    }

    _endGame(success) {
        if (!this.gameActive) return;
        this.gameActive = false;
        if (success) {
            const snd = this.sound.add('ddComplete', { volume: 0.8 });
            snd.once('complete', () => snd.destroy());
            snd.play();
        }
        const msg = success ? 'ALL DOTS EATEN!' : 'GHOST GOT YOU!';
        const color = success ? '#ffff00' : '#ff4444';
        this.add.text(800, 440, msg, {
            fontSize: '72px', fontFamily: 'monospace',
            color, stroke: '#000000', strokeThickness: 5,
        }).setOrigin(0.5).setDepth(20);
        this.time.delayedCall(2200, () => {
            this.game.events.emit('miniGameResult', { success });
        });
    }
}
