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

export class Board {
    constructor() {
        this.slots = [];
        this.balls = [];
	/*
	Design and color pallet by @kateradeg
	*/
        this.heldBall = null;
        this.removedFromSlot = null;
        this.game = null;

        this.levelData = "";
        this.canvasBounds = null;
    }

    init(game) {
        this.game = game;
        this.reset();
    }

    reset() {
        this.loadLevel();
        // this.generateRandomLevel();
        
    }

    generateRandomLevel() {
        this.balls = [];
        this.slots = [];

        let slotCount = 2;
        let level = this.game.playerData.current;
        switch(level) {
            case 1:
            case 2:
                slotCount = 2;
                break;
            case 3:
            case 4:
            case 5:
            case 6:
                slotCount = 4;
                break;
            case 7:
            case 8:
            case 9:
            case 10:
            case 11:
                slotCount = 6;
                break;
            case 12:
            case 13:
            case 14:
            case 15:
            case 16:
                slotCount = 8;
                break;
            case 17:
            case 18:
            case 19:
            case 20:
            case 21:
            case 22:
                slotCount = 10;
                break;
            default:
                slotCount = 12;
                break;
        }
        for(let i = 0; i < slotCount; i++){
            for(let j = 0; j < 4; j++) {
                this.balls.push(new Ball(i));
            }
        }

        this.balls = this.shuffle(this.balls);

        for(let i = 0; i < slotCount; i++){
            let slot = new Slot(i);
            for(let j = 0; j < 4; j++) {
                slot.addBall(this.balls[4*i+j]);
            }
            this.slots.push(slot);
        }

        this.slots.push(new Slot(slotCount)); //two empties
        this.slots.push(new Slot(slotCount+1));

        //this.levelData += "\t" + JSON.stringify({slots: this.slots.length, balls:this.balls.map(b => b.colorId)}) +",\n";
    }

    shuffle(a) {
        var j, x, i;
        for (i = a.length - 1; i > 0; i--) {
            j = Math.floor(Math.random() * (i + 1));
            x = a[i];
            a[i] = a[j];
            a[j] = x;
        }
        return a;
    }

    loadLevel() {
        this.balls = [];
        this.slots = [];

        let level = this.game.playerData.current;
        let levelData = this.game.getLevel(level);
        if(!levelData) {
            this.generateRandomLevel();
            return;
        }

        this.balls = levelData.balls.map(colorId => new Ball(colorId));
        for(let i = 0; i < levelData.slots-2; i++){
            let slot = new Slot(i);
            for(let j = 0; j < 4; j++) {
                slot.addBall(this.balls[4*i+j]);
            }
            this.slots.push(slot);
        }
        this.slots.push(new Slot(levelData.slots-2));
        this.slots.push(new Slot(levelData.slots-1));
    }

    draw(ctx, scaledCanvas) {
        this.canvasBounds = scaledCanvas.bounds;

        ctx.strokeStyle = "rgba(255,255,255,0.5)";
        ctx.fillStyle = "rgba(255,255,255,0.3)";
        ctx.lineWidth = 3;
        for(let i = 0; i < this.slots.length; i++) {
            let slotBounds = this.getSlotBounds(this.slots[i]);
            ctx.save();
            ctx.translate(slotBounds.x, slotBounds.y);
            this.slots[i].draw(ctx, scaledCanvas);
            ctx.restore();
        }

        if(this.heldBall) {
            let bounds = this.getSlotBounds(this.removedFromSlot);
            ctx.save();
            let radiusPadding = Ball.radius + Ball.radiusPadding;
            ctx.translate(bounds.x + Slot.width / 2, bounds.y - radiusPadding);
            this.heldBall.draw(ctx, scaledCanvas);
            ctx.restore();
        }
    }

    update(delta) {
    }

    mouseDown(event) {
        let mousePoint = new Point(event.clientX, event.clientY);
        for(let i = 0; i < this.slots.length; i++) {
            let slot = this.slots[i];
            if(this.getSlotBounds(slot).pointWithin(mousePoint)) {
                if(!this.heldBall) {
                    this.heldBall = slot.removeBall();
                    this.removedFromSlot = slot;
                } else {
                    if(slot.canAddBall(this.heldBall) || slot == this.removedFromSlot) {
                        this.game.trackMove(this.removedFromSlot, slot);
                        this.placeHeldBallInSlot(slot);
                        this.checkForWin();
                    }
                }
            }
        }
    }

    mouseMove(event) {
        let mousePoint = new Point(event.clientX, event.clientY);
        for(let i = 0; i < this.slots.length; i++) {
            let slot = this.slots[i];
            if(this.getSlotBounds(slot).pointWithin(mousePoint)) {
                document.body.style.cursor = "pointer";
            }
        }
    }

    placeHeldBallInSlot(slot) {
        slot.addBall(this.heldBall);
        this.heldBall = null;
        this.removedFromSlot = null;
    }

    getSlotBounds(slot) {
        let widthPadding = Slot.width + Slot.widthPadding;
        let heightPadding = Slot.height + Slot.heightPadding;
        let radiusPadding = Ball.radius + Ball.radiusPadding;

        let maxSlotsPerRow = Math.floor((this.canvasBounds.width - 40) / widthPadding);
        let slotsInFirstRow = Math.min(this.slots.length, maxSlotsPerRow);
        if(slotsInFirstRow < this.slots.length) {
            slotsInFirstRow = this.slots.length / 2;
        }
        let slotsTotalWidth = slotsInFirstRow * widthPadding;
        let offsetX = (this.canvasBounds.width - slotsTotalWidth - 40 + widthPadding) / 2
        return new Rectangle(
            offsetX + (slot.id % slotsInFirstRow) * widthPadding,
            Math.floor(slot.id / slotsInFirstRow) * heightPadding + Math.max((2 * radiusPadding), this.canvasBounds.height < 660 ?  10 : this.canvasBounds.height / 4),
            Slot.width,
            Slot.height + radiusPadding,
        );
    }

    checkForWin() {
        if(this.hasWon()) {
            this.game.win();
        }
    }

    hasWon() {
        for(let i = 0; i < this.slots.length; i++) {
            let slot = this.slots[i];
            if(!slot.colorsAllMatch()) {
                return false;
            }
        }
        return true;
    }

    initDemo() {
        //this.levelData = "[\n";
        //for(let i = 1; i< 256; i++) {
            this.game = {playerData: {current: 15}};
            this.generateRandomLevel();
        //}
        //this.levelData += "]\n";

        //console.log(this.levelData);
    }

    drawDemo(ctx, scaledCanvas) {
        this.draw(ctx,scaledCanvas);
    }
    
    getBounds() {
        let firstSlotBounds = this.getSlotBounds(this.slots[0]);
        let lastSlotBounds = this.getSlotBounds(this.slots[this.slots.length - 1]);

        return new Rectangle(
            firstSlotBounds.x,
            firstSlotBounds.y,
            lastSlotBounds.x - firstSlotBounds.x + lastSlotBounds.width,
            lastSlotBounds.y - firstSlotBounds.y + lastSlotBounds.height,
            )
    }
}
