import { Point } from "../../libraries/spatial/Point.js";
import { Rectangle } from "../../libraries/spatial/Rectangle.js";
import { Board } from "../Board.js";
import {Slot} from "../Slot.js";

export class GameState {
    constructor(fsm) {
        this.stateMachine = fsm;
        this.board = null;
        this.playerData = {current: 1, level: 1};
        this.canvasBounds = null;
        this.showNextButton = false;
        this.showUndoButton = false;
        this.movelist = [];
        this.boundMouseEvent = {};
        this.levelData = [];
    }

    init() {
        this.board = new Board();
        this.board.init(this);
        this.boundMouseEvent['mousedown'] = this.mouseDown.bind(this);
        this.boundMouseEvent['mousemove'] = this.mouseMove.bind(this);
        for(let key in this.boundMouseEvent) {
            window.addEventListener(key, this.boundMouseEvent[key]);
        }

        //TODO: replace next button
        //TODO: replace undo button
    }

    setLevelData(data) {
        this.levelData = data;
    }

    getLevelData() {
        return this.levelData;
    }

    setPlayerData(data) {
        this.playerData = data;
    }

    getPlayerData() {
        return this.playerData;
    }

    getLevel(levelId) {
        return this.getLevelData()[levelId];
    }

    draw(ctx, scaledCanvas) {
        this.canvasBounds = scaledCanvas.bounds;
         try {
            ctx.fillStyle = "white";
            ctx.strokeStyle = "black";
            ctx.font = "48px Luckiest Guy";
            ctx.textAlign = "center";
            ctx.lineWidth = 4;
            ctx.fillText(`Level ${this.playerData.current}`, scaledCanvas.center.x, 48);
            ctx.strokeText(`Level ${this.playerData.current}`, scaledCanvas.center.x, 48);

            if(this.showNextButton) {
                this.drawNextButton(ctx, scaledCanvas);
            }

            if(this.showUndoButton) {
                this.drawUndoButton(ctx, scaledCanvas);
            }

            this.board.draw(ctx, scaledCanvas);

        } catch(e) {
            ctx.setTransform(1, 0, 0, 1, 0, 0);
            ctx.fillStyle = 'crimson';
            ctx.font = "32px Arial";
            ctx.fontAlign = "left";
            ctx.fillText(`error: ${e.message}`, 4, 32);
            console.error(e);
        }

        if(this.showWinDialog) {
            this.drawWinDialog(ctx, scaledCanvas);
        }
    }

    update(delta) {
        this.board.update(delta);
    }

    drawNextButton(ctx, scaledCanvas) {
        let bounds = this.getNextButtonBounds();

        ctx.fillStyle = "rgba(255,255,255,0.5)";
        ctx.save();
        ctx.translate(bounds.x, bounds.y);
        ctx.beginPath();
        ctx.moveTo(bounds.width, bounds.height / 2);
        ctx.lineTo(bounds.width / 2, bounds.height);
        ctx.lineTo(bounds.width / 2, 0);
        ctx.closePath();
        ctx.fill();

        ctx.fillStyle = "white";
        ctx.font = "24px Arial";
        ctx.textAlign = "left";
        ctx.fillText(`next`, 0, bounds.height/2 + 8);
        ctx.restore();
    }

    drawUndoButton(ctx, scaledCanvas) {
        let bounds = this.getUndoButtonBounds();
        ctx.fillStyle = "rgba(255,255,255,0.5)";
        ctx.save();
        ctx.translate(bounds.x, bounds.y);
        ctx.beginPath();
        ctx.rect(0, 0, bounds.width, bounds.height);
        ctx.closePath();
        ctx.fill();

        ctx.fillStyle = "white";
        ctx.font = "24px Arial";
        ctx.textAlign = "center";
        let undoText = this.movelist.length < 9 ? `undo (${this.movelist.length})` : `undo`;
        ctx.fillText(undoText, bounds.width / 2, bounds.height - 20);
        ctx.restore();
    }

    drawWinDialog(ctx, scaledCanvas) {
        let bounds = scaledCanvas.bounds;
        ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
        ctx.beginPath();
        ctx.rect(bounds.width / 4, bounds.height / 4 + bounds.height / 16, bounds.width / 2, bounds.height / 8);
        ctx.closePath();
        ctx.fill();

        ctx.fillStyle = "white";
            ctx.strokeStyle = "black";
            ctx.font = "48px Luckiest Guy";
            ctx.textAlign = "center";
            ctx.lineWidth = 4;
            ctx.fillText(`You Win!`, bounds.center.x, bounds.height / 2 - bounds.height / 8 + 12);
            ctx.strokeText(`You Win!`, bounds.center.x,  bounds.height / 2 - bounds.height / 8 + 12);
    }

    mouseDown(event) {
        let mousePoint = new Point(event.clientX, event.clientY);
        let nextBounds = this.getNextButtonBounds();
        if(this.showNextButton && nextBounds.pointWithin(mousePoint)) {
            if(this.playerData.level == this.playerData.current) {
                this.playerData.level++;
            }
            this.playerData.current++;
            localStorage.setItem('ballsort-playerdata', JSON.stringify(this.playerData));
            this.board.reset();
            this.showNextButton = false;
            this.showWinDialog = false;
        }

        if(this.showUndoButton) {
            let undoBounds = this.getUndoButtonBounds();
            if(undoBounds.pointWithin(mousePoint)) {
                this.undo();
            }
        }

        if(!this.showWinDialog) {
            this.board.mouseDown(event);
        }
    }

    mouseMove(event) {
        document.body.style.cursor = "default";

        let mousePoint = new Point(event.clientX, event.clientY);
        if(this.showNextButton) {
            let nextBounds = this.getNextButtonBounds();
            if(nextBounds.pointWithin(mousePoint)) {
                document.body.style.cursor = "pointer";
            }
        }

        if(this.showUndoButton) {
            let undoBounds = this.getUndoButtonBounds();
            if(undoBounds.pointWithin(mousePoint)) {
                document.body.style.cursor = "pointer";
            }
        }
        if(!this.showWinDialog) {
            this.board.mouseMove(event);
        }
    }

    trackMove(fromSlot, toSlot) {
        let move = {from: fromSlot, to: toSlot};
        this.movelist.push(move);
        this.showUndoButton = this.movelist.length > 0;
    }

    undo() {
        if(this.board.heldBall) {
            this.board.placeHeldBallInSlot(this.board.removedFromSlot);
            return;
        }
        let move = this.movelist.pop();
        if(move) {
            let ball = move.to.removeBall();
            move.from.addBall(ball);
        }
        this.showUndoButton = this.movelist.length > 0;
    }

    getNextButtonBounds() {
        let boardBounds = this.board.getBounds();
        let position = {
            x: this.canvasBounds.center.x,
            y:  boardBounds.y + boardBounds.height + 20,
        }
        if(this.canvasBounds.height < 660) {
            position.x = this.canvasBounds.width - 100;
            position.y = Slot.height + (Slot.heightPadding / 2) + boardBounds.y - 25;
        }
        return new Rectangle(position.x, position.y, 100, 50);
    }

    getUndoButtonBounds() {
        let boardBounds = this.board.getBounds();
        let position = {
            x: this.canvasBounds.center.x,
            y: boardBounds.y + boardBounds.height + 20,
        }
        if(this.canvasBounds.height < 660) {
            position.x = this.canvasBounds.width - 100;
            position.y = Slot.height + (Slot.heightPadding / 2) + boardBounds.y - 25;
        }
        return new Rectangle(position.x, position.y, 100, 50);
    }

    win() {
        setTimeout(() => {
            this.showWinDialog = true;
            this.showNextButton = true;
            this.showUndoButton = false;
            this.movelist = [];
        }, 400);
        
    }

    enter() {
        this.init(this.stateMachine.getState("game"));
    }
    leave() {
        this.board.destroy();
        for(let key in this.boundMouseEvent) {
            window.removeEventListener(key, this.boundMouseEvent[key]);
        }
    }
}
