import { Sketch } from "treehouse/sandbox.js";

export class TileEditor extends Sketch {
    constructor({ tilemap, tileSize }) {
        super(tilemap.width * tileSize, tilemap.height * tileSize);

        this.colorScheme = {
            background: "#F7F7F7",
            grid: "#00000011",
            tileCursor: "#222222",
            tiles: [
                "transparent", // never actually drawn to the screen with the default renderer!
                "#eb134a",
            ],
        };

        this.tilemap = tilemap;
        this.tileSize = tileSize;

        this.hasFocus = false;
        this.paintingTile = null;
        this.tileCursor = { x: 0, y: 0 };

        this.canvas.addEventListener("mousemove", event => this.mouseMoved(event));
        this.canvas.addEventListener("mousedown", event => this.mousePressed(event));
        this.canvas.addEventListener("mouseup", event => this.mouseReleased(event));

        this.canvas.addEventListener("mouseenter", _ => this.mouseEnter());
        this.canvas.addEventListener("mouseleave", _ => this.mouseLeave());

        this.canvas.addEventListener("contextmenu", event => event.preventDefault());

        // Only draw first frame after the constructor already runs.
        // That way we can modify the color scheme however much we want without causing additional
        // redraws.
        requestAnimationFrame(() => this.draw());
    }

    draw() {
        this.drawBackground();
        this.drawTilemap();
        this.drawGrid();
        if (this.hasFocus) {
            this.drawTileCursor();
        }
    }

    drawBackground() {
        this.ctx.fillStyle = this.colorScheme.background;
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
    }

    drawTilemap() {
        for (let y = 0; y < this.tilemap.height; ++y) {
            for (let x = 0; x < this.tilemap.width; ++x) {
                let tile = this.tilemap.at(x, y);
                if (tile != 0) {
                    this.ctx.fillStyle = this.colorScheme.tiles[tile];
                    this.ctx.fillRect(x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize);
                }
            }
        }
    }

    drawGrid() {
        this.ctx.beginPath();
        for (let x = 0; x < this.tilemap.width; ++x) {
            this.ctx.moveTo(x * this.tileSize, 0);
            this.ctx.lineTo(x * this.tileSize, this.canvas.height);
        }
        for (let y = 0; y < this.tilemap.width; ++y) {
            this.ctx.moveTo(0, y * this.tileSize);
            this.ctx.lineTo(this.canvas.width, y * this.tileSize);
        }
        this.ctx.strokeStyle = this.colorScheme.grid;
        this.ctx.lineWidth = 1;
        this.ctx.stroke();
    }

    drawTileCursor() {
        this.ctx.strokeStyle = this.colorScheme.tileCursor;
        this.ctx.lineWidth = 5;
        this.ctx.strokeRect(this.tileCursor.x * this.tileSize, this.tileCursor.y * this.tileSize, this.tileSize, this.tileSize);
    }


    mouseMoved(event) {
        this.tileCursor.x = Math.floor(event.offsetX / this.tileSize);
        this.tileCursor.y = Math.floor(event.offsetY / this.tileSize);
        this.paintTileUnderCursor();

        this.draw();
    }

    mousePressed(event) {
        event.preventDefault();

        if (event.button == 0) {
            this.paintingTile = 1;
        } else if (event.button == 2) {
            this.paintingTile = 0;
        }

        this.paintTileUnderCursor();

        this.draw();
    }

    mouseReleased(_event) {
        this.stopPainting();
        this.draw();
    }

    mouseEnter() {
        this.hasFocus = true;
        this.draw();
    }

    mouseLeave() {
        this.hasFocus = false;
        this.stopPainting();
        this.draw();
    }

    paintTileUnderCursor() {
        if (this.paintingTile != null) {
            this.tilemap.setAt(this.tileCursor.x, this.tileCursor.y, this.paintingTile);
        }
    }

    stopPainting() {
        this.paintingTile = null;
    }
}