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

export class GridSystem {
    /**
     * The GridSystem maintains the "Source of Truth" for the dungeon layout.
     * It knows which cells are occupied and by whom.
     * Dependencies: Constants.js (DIRECTIONS)
     */
    constructor() {
        // We use a Map for O(1) lookups.
        // Key: "x,y" (String) -> Value: "tileId" (String)
        this.occupiedCells = new Map();

        // We also keep a list of placed tile objects for easier iteration if needed later.
        this.tiles = [];
    }

    /**
     * Checks if a tile can be placed at the given coordinates with the given rotation.
     * Needs: The Tile Definition (to know size), the target X,Y, and desired Rotation.
     */
    canPlace(tileDef, startX, startY, rotation) {
        // 1. Calculate the real-world coordinates of every single cell this tile would occupy.
        const cells = this.getGlobalCells(tileDef, startX, startY, rotation);

        // 2. Check each cell against our Map of occupied spots.
        for (const cell of cells) {
            const key = `${cell.x},${cell.y}`;
            if (this.occupiedCells.has(key)) {
                return false; // COLLISION! Spot already taken.
            }
        }
        return true; // All clear.
    }

    /**
     * Officially registers a tile onto the board.
     * Should only be called AFTER canPlace returns true.
     */
    placeTile(tileInstance, tileDef) {
        const cells = this.getGlobalCells(tileDef, tileInstance.x, tileInstance.y, tileInstance.rotation);

        // Record every cell in our Map
        for (const cell of cells) {
            const key = `${cell.x},${cell.y}`;
            this.occupiedCells.set(key, tileInstance.id);
        }

        // Store the instance
        this.tiles.push(tileInstance);
        console.log(`Placed tile ${tileInstance.id} at ${tileInstance.x},${tileInstance.y}`);
    }

    /**
     * THE CORRECTED MAGIC MATH FUNCTION.
     * Now uses Pre-Calculated Variants from TileDefinitions.
     * NO DYNAMIC ROTATION MATH performed here.
     * All variants are treated as "North" oriented blocks.
     */
    getGlobalCells(tileDef, startX, startY, rotation) {
        const cells = [];

        // 1. Retrieve the specific variant for this rotation
        const variant = tileDef.variants[rotation];
        if (!variant) {
            console.error(`Missing variant for rotation ${rotation} in tile ${tileDef.id}`);
            return cells;
        }

        const layout = variant.layout;

        if (!layout) {
            console.error("Variant missing layout. ID:", tileDef?.id, rotation);
            return cells;
        }

        const numberOfRows = layout.length;

        // Iterate through matrix rows
        for (let row = 0; row < numberOfRows; row++) {
            const rowData = layout[row];
            const numberOfCols = rowData.length;

            for (let col = 0; col < numberOfCols; col++) {
                const cellValue = rowData[col];

                // Skip empty cells (0)
                if (cellValue === 0) continue;

                // Map Matrix (Row, Col) to Local Grid (lx, ly)
                // Matrix Row 0 is the "Top" (Max Y) relative to the tile's origin
                // Matrix Row (Rows-1) is the "Bottom" (Y=0)
                // lx grows right (col)
                // ly grows up (rows reversed)
                const lx = col;
                const ly = (numberOfRows - 1) - row;

                // SIMPLIFIED LOGIC:
                // Since the variant layout is ALREADY rotated, we always just ADD the offsets.
                // We treat every variant as if it's placed "North-wise" at the anchor point.

                const gx = startX + lx;
                const gy = startY + ly;

                cells.push({ x: gx, y: gy, value: cellValue });
            }
        }
        return cells;
    }

    /**
     * Transforms a local point (like an exit definition) to Global Coordinates.
     * Simplified: Just adds offsets because variants carry pre-rotated coords.
     */
    getGlobalPoint(localX, localY, tileInstance) {
        const startX = tileInstance.x;
        const startY = tileInstance.y;

        // Simple translation. Rotation is handled by the variant properties upstream.
        return {
            x: startX + localX,
            y: startY + localY
        };
    }

    /**
     * DEPRECATED / LEGACY
     * Kept just in case, but shouldn't be needed with explicit variants.
     */
    getRotatedDirection(originalDirection, tileRotation) {
        // With explicit variants, the exit.direction is ALREADY the final global direction.
        return originalDirection;
    }
}
