import MrCroc from "./MrCroc.js";
import Gisela from "./Gisela.js";
import RetroArchitecture from "./retro/RetroArchitecture.js";
import Camera from "./Camera.js";
import TextMessageMrCroc from "./ui/TextMessageMrCroc.js";
import TextMessageGisela from "./ui/TextMessageGisela.js";
import UserInterface from "./ui/UserInterface.js";
import Key from "./Key.js";
import Setting from "./Setting.js";
import {EventBus} from "./events/EventBus.js";


export class Game
{
    static GAME_SPEED = 1

    constructor(level) {
        this.level = level;
        this.fps = 60;
        this.frameDuration = 1000.0 / this.fps;
        this.lastRendered = undefined;
        this.lastTimestamp = undefined;
        this.canvas = document.getElementById('canvas');
        this.context = this.canvas.getContext('2d');
        this.mrCroc = new MrCroc();
        this.gisela = new Gisela();
        this.architecture = RetroArchitecture.createFromData(this.level);

        const cameraPosition = this.architecture.getStartPosition();

        this.camera = new Camera(cameraPosition.x, cameraPosition.y);
        this.gameFinished = false;
        this.hasPlayerLeftArchitecture = false;
        this.textBoxGameStart = new TextMessageMrCroc('Mr. Croc: "Where is Gisela? I have to find her!"', this.context);
        this.textBoxGameFinished = new TextMessageGisela(
            'Gisela: "Thanks for showing up, Mr. Croc, but I\'m not in danger."',
            this.context
        );
        this.userInterface = new UserInterface();
        this.isPaused = true;

        this.KeyLeft = new Key('ArrowLeft');
        this.KeyRight = new Key('ArrowRight');
        this.KeyJump = new Key('Space');
        this.KeyLoad = new Key('KeyL');
    }

    render(timestamp)
    {
        if (timestamp - this.lastRendered < this.frameDuration) {
            return;
        }

        /*
        if (this.gisela.currentAnimation !== 'SLEEP_LEFT' && this.mrCroc.position.x < this.gisela.position.x) {
            this.gisela.currentAnimation = 'SLEEP_LEFT';
        } else if (this.gisela.currentAnimation !== 'SLEEP_RIGHT' && this.mrCroc.position.x >= this.gisela.position.x) {
            this.gisela.currentAnimation = 'SLEEP_RIGHT';
        }
        */

        if (!this.gameFinished) {
            if (this.mrCroc.position.x < this.gisela.position.x) {
                this.gisela.playAnimation('SLEEP_LEFT', timestamp);
            } else {
                this.gisela.playAnimation('SLEEP_RIGHT', timestamp);
            }
        }

        this.context.clearRect(0, 0, window.innerWidth, window.innerHeight);
        this.architecture.draw(this.context, this.camera);
        this.gisela.draw(this.context, this.camera);
        this.mrCroc.draw(this.context, this.camera);

	for (const effect of this.level.fullscreenEffects) {
		effect.update(timestamp);
		effect.render(this.context, this.camera);
	}

	this.userInterface.draw(this.context);

        this.lastRendered = timestamp;
    }

    canBeFinished()
    {
        return (
            !this.gameFinished &&
            this.mrCroc.isJumping === false &&
            this.architecture.isMovableInsideTargetPosition(this.mrCroc)
        );
    }

    handlePhysics(delta, timestamp)
    {
        const ceilingHeight = Math.max(
            this.architecture.getCeilingHeight(this.mrCroc.getPositionHeadLeft()),
            this.architecture.getCeilingHeight(this.mrCroc.getPositionHeadRight()),
        );

        const groundHeight = Math.min(
            this.architecture.getGroundHeight(this.mrCroc.getPositionFootLeft()),
            this.architecture.getGroundHeight(this.mrCroc.getPositionFootRight())
        );

        /* Handle falling */
        this.mrCroc.position.y += this.mrCroc.fallSpeed * delta * 0.6;
        this.mrCroc.fallSpeed += this.level.gravity * delta;

        /* Handle ground collision */
        if (this.mrCroc.position.y > groundHeight && this.mrCroc.fallSpeed > 0) {
            this.mrCroc.position.y = groundHeight;
            this.mrCroc.fallSpeed = 0;
        }

        /* Handle ceiling collision */
        if (this.mrCroc.position.y - this.mrCroc.getHeight() <= ceilingHeight) {
            this.mrCroc.fallSpeed = 0;
            this.mrCroc.position.y = ceilingHeight + this.mrCroc.getHeight() + 1;
        }

        this.handlePlayerMovement(delta, timestamp, groundHeight);
    }

    updateCamera()
    {
        this.camera.focusPosition(
            this.mrCroc.position.x - this.mrCroc.getWidth() * 0.5,
            this.mrCroc.position.y - this.mrCroc.getHeight() * 0.5,
            20
        );
        this.camera.lockCameraIntoBorders();
    }

    handlePlayerMovement(delta, timestamp, groundHeight)
    {
        /* Jumping */
        if (!this.mrCroc.isJumping && this.mrCroc.fallSpeed === 0 && this.mrCroc.position.y === groundHeight && this.KeyJump.isPressed()) {
            this.mrCroc.jump();
        } else if (!this.KeyJump.isPressed()) {
            this.mrCroc.isJumping = false;
        }

        /* Movement left and right */
        if (!this.hasPlayerLeftArchitecture && this.KeyLeft.isPressed()) {
            const lastWallLeft = Math.min(
                this.architecture.getWallLeft(this.mrCroc.getPositionHeadLeft()),
                this.architecture.getWallLeft(this.mrCroc.getPositionFootLeft())
            );

            this.mrCroc.moveLeft(timestamp, delta);

            if (this.mrCroc.position.x <= lastWallLeft + this.mrCroc.getWidth() * 0.5) {
                this.mrCroc.position.x = lastWallLeft + this.mrCroc.getWidth() * 0.5 + 1;
            }
        } else if (!this.hasPlayerLeftArchitecture && this.KeyRight.isPressed()) {
            const lastWallRight = Math.max(
                this.architecture.getWallRight(this.mrCroc.getPositionHeadRight()),
                this.architecture.getWallRight(this.mrCroc.getPositionFootRight())
            );

            this.mrCroc.moveRight(timestamp, delta);

            if (this.mrCroc.position.x >= lastWallRight - this.mrCroc.getWidth() * 0.5) {
                this.mrCroc.position.x = lastWallRight - this.mrCroc.getWidth() * 0.5 - 1;
            }
        }

        if (!this.hasPlayerLeftArchitecture && !this.architecture.isInsideArchitecture(this.mrCroc.position)) {
            this.hasPlayerLeftArchitecture = true;

            setTimeout(
                () => {
                    this.architecture.setMovableToStartPosition(this.mrCroc);
                    this.hasPlayerLeftArchitecture = false;
                }, 2000
            );
        }
    }

    finish()
    {
        if (this.mrCroc.position.x < this.gisela.position.x) {
            this.gisela.currentAnimation = 'LOOK_LEFT';
        } else {
            this.gisela.currentAnimation = 'LOOK_RIGHT';
        }

        this.gameFinished = true;
        this.KeyLeft.pressed = false;
        this.KeyRight.pressed = false;
        this.KeyJump.pressed = false;
        this.lastTimestamp = undefined;
        this.lastRendered = undefined;
        this.textBoxGameFinished.updateLines(window.innerWidth - 40, this.context);
        this.textBoxGameFinished.animate(75);
        this.userInterface.addTextBox(this.textBoxGameFinished);
    }

    init(loopFunction) {
        if (this.isChromeBrowser()) {
            this.canvas.width = window.innerWidth - 1;
            this.canvas.height = window.innerHeight - 1;
        }

        this.canvas.style.backgroundAttachment = 'fixed';
        this.canvas.style.backgroundSize = 'cover';
        this.canvas.style.backgroundPosition = 'center center';

        if (this.level.getBackgroundImage() !== undefined) {
            this.canvas.style.backgroundImage = "url("+ Setting.GRAPHICS_LOCATION + this.level.getBackgroundImage() + ")";
        } else {
            this.canvas.style.backgroundImage = 'none';
        }

        this.canvas.style.backgroundColor = this.level.getBackgroundColor();
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;

        EventBus.addEventListener(
            'resize',
            function () {
                this.canvas.width = window.innerWidth;
                this.canvas.height = window.innerHeight;
            }
        );

        this.textBoxGameStart.animate(75, 1000);
        this.textBoxGameStart.show(1000);
        this.textBoxGameStart.hide(10000);
        this.userInterface.addTextBox(this.textBoxGameStart);

        this.camera.borderRight = this.architecture.columns * this.architecture.tileWidth;
        this.camera.borderBottom = this.architecture.rows * this.architecture.tileHeight;

        this.architecture.setMovableToStartPosition(this.mrCroc);
        this.architecture.setMovableToTargetPosition(this.gisela);

        this.isPaused = false;

        for (const effect of this.level.fullscreenEffects) {
            effect.init();
        }

        window.requestAnimationFrame(loopFunction);
    }

    isChromeBrowser()
    {
        return navigator.userAgent.match('Chrome') !== null;
    }
}
