import { DIRECTIONS } from './Constants.js';
import { GridSystem } from './GridSystem.js';
import { DungeonDeck } from './DungeonDeck.js';

export class DungeonGenerator {
    constructor() {
        this.grid = new GridSystem();
        this.deck = new DungeonDeck();
        this.pendingExits = [];
        this.placedTiles = [];
        this.isComplete = false;
    }

    startDungeon(missionConfig) {
        const objectiveId = missionConfig?.type === 'quest' ? 'room_objective' : 'room_dungeon';
        this.deck.generateMissionDeck(objectiveId);

        const firstCard = this.deck.draw();
        if (!firstCard) {
            console.error("❌ Deck empty!");
            return;
        }

        // Place first tile with NORTH variant
        this.placeTileAt(firstCard, 0, 0, DIRECTIONS.NORTH);
        console.log(`🏰 Dungeon started with ${firstCard.name}`);
    }

    step() {
        if (this.isComplete || this.pendingExits.length === 0) {
            this.isComplete = true;
            return false;
        }

        const card = this.deck.draw();
        if (!card) {
            this.isComplete = true;
            return false;
        }

        const targetExit = this.pendingExits.shift();
        const placed = this.tryPlaceCard(card, targetExit);

        if (!placed) {
            this.pendingExits.push(targetExit);
            console.warn(`⚠️ Failed to place ${card.name} - returning exit to pending queue`);
        }

        return true;
    }

    tryPlaceCard(card, targetExit) {
        console.log(`\n🃏 Trying to place card: ${card.name} (ID: ${card.id})`);

        // Use standard opposite logic for Directions (String) since names don't change
        const requiredDirection = this.opposite(targetExit.direction);
        const targetCell = this.neighbor(targetExit.x, targetExit.y, targetExit.direction);

        const rotations = [DIRECTIONS.NORTH, DIRECTIONS.EAST, DIRECTIONS.SOUTH, DIRECTIONS.WEST];
        const shuffled = this.shuffle(rotations);

        let bestPlacement = null;
        let maxConnections = -1;

        // Try ALL rotations
        for (const rotation of shuffled) {
            // 1. Get the pre-calculated VARIANT for this rotation
            const variant = card.variants[rotation];
            if (!variant) continue;

            const variantExits = variant.exits;

            // 2. Find candidate exits on this variant that face the required direction
            // Note: variant.exits are ALREADY correctly oriented for this rotation
            const candidates = variantExits.filter(e => e.direction === requiredDirection);

            for (const candidate of candidates) {
                // Determine absolute anchor position
                // Since variant coords are all positive relative to (0,0), anchor calculation is simple subtraction
                const anchorX = targetCell.x - candidate.x;
                const anchorY = targetCell.y - candidate.y;

                if (this.grid.canPlace(card, anchorX, anchorY, rotation)) {
                    // Start Score at 0
                    let score = 0;

                    // Calculate score
                    for (const exit of variantExits) {
                        const globalX = anchorX + exit.x;
                        const globalY = anchorY + exit.y;

                        const neighbor = this.neighbor(globalX, globalY, exit.direction);
                        const neighborKey = `${neighbor.x},${neighbor.y}`;

                        if (this.grid.occupiedCells.has(neighborKey)) {
                            score++;
                        }
                    }

                    // Prefer higher score. 
                    if (score > maxConnections) {
                        maxConnections = score;
                        bestPlacement = { card, anchorX, anchorY, rotation };
                    }
                }
            }
        }

        if (bestPlacement) {
            this.placeTileAt(bestPlacement.card, bestPlacement.anchorX, bestPlacement.anchorY, bestPlacement.rotation);
            console.log(`✅ Placed ${card.name} at (${bestPlacement.anchorX}, ${bestPlacement.anchorY}) Rot:${bestPlacement.rotation} Score:${maxConnections}`);
            return true;
        }

        console.log(`❌ Could not place ${card.name} in any rotation`);
        return false;
    }

    placeTileAt(tileDef, x, y, rotation) {
        const instance = {
            id: `tile_${this.placedTiles.length}`,
            defId: tileDef.id,
            x, y, rotation
        };

        this.grid.placeTile(instance, tileDef); // Grid system now handles looking up the variant
        this.placedTiles.push(instance);

        // Add exits from the variant
        const variant = tileDef.variants[rotation];

        for (const exit of variant.exits) {
            const globalX = x + exit.x;
            const globalY = y + exit.y;
            const neighborCell = this.neighbor(globalX, globalY, exit.direction);
            const key = `${neighborCell.x},${neighborCell.y}`;

            // Only add exit if it leads to empty space
            if (!this.grid.occupiedCells.has(key)) {
                this.pendingExits.push({
                    x: globalX,
                    y: globalY,
                    direction: exit.direction
                });
            }
        }

        // Cleanup pending exits that are now connected
        this.pendingExits = this.pendingExits.filter(ex => {
            const n = this.neighbor(ex.x, ex.y, ex.direction);
            return !this.grid.occupiedCells.has(`${n.x},${n.y}`);
        });
    }

    neighbor(x, y, direction) {
        switch (direction) {
            case DIRECTIONS.NORTH: return { x, y: y + 1 };
            case DIRECTIONS.SOUTH: return { x, y: y - 1 };
            case DIRECTIONS.EAST: return { x: x + 1, y };
            case DIRECTIONS.WEST: return { x: x - 1, y };
        }
    }

    opposite(direction) {
        switch (direction) {
            case DIRECTIONS.NORTH: return DIRECTIONS.SOUTH;
            case DIRECTIONS.SOUTH: return DIRECTIONS.NORTH;
            case DIRECTIONS.EAST: return DIRECTIONS.WEST;
            case DIRECTIONS.WEST: return DIRECTIONS.EAST;
        }
    }

    shuffle(arr) {
        const copy = [...arr];
        for (let i = copy.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [copy[i], copy[j]] = [copy[j], copy[i]];
        }
        return copy;
    }
}
