import { SimMain } from "../Simulation/index.js";
import { VisLevel } from "./index.js";

export class VisMain {
    private _canvas: HTMLCanvasElement;
    private _context: CanvasRenderingContext2D;
    private _startTimestamp: number = 0;
    private _active: boolean = true;
    private _ready: boolean = false;
    private _gap: number = 0;
    private _wallPattern: CanvasPattern;
    private _visLevel: VisLevel;
    private _simMain: SimMain;

    constructor(simMain: SimMain, canvas: HTMLCanvasElement) {
        this._simMain = simMain;
        this._canvas = canvas;
        this._context = this._canvas.getContext("2d")!;
        this._context.globalCompositeOperation = "source-over";
        this._wallPattern = this.createPattern(this._simMain.gdRoot.image("wall.png"), 48);
        this._visLevel = new VisLevel(this, this._simMain, this._simMain.gdRoot);
        const host = this;
        requestAnimationFrame(function step(timestamp) {
            host.step(timestamp);
        });
    }

    public get simMain(): SimMain {
        return this._simMain;
    }

    public get visLevel(): VisLevel {
        return this._visLevel;
    }

    public get canvas(): HTMLCanvasElement {
        return this._canvas;
    }

    public get context(): CanvasRenderingContext2D {
        return this._context;
    }

    public get wallPattern(): CanvasPattern {
        return this._wallPattern;
    }

    private createPattern(image: HTMLImageElement, size: number): CanvasPattern {
        const tempCanvas = document.createElement("canvas");
        const tempContext = tempCanvas.getContext("2d")!;

        tempCanvas.width = size;
        tempCanvas.height = size;
        tempContext.drawImage(image, 0, 0, image.width, image.height, 0, 0, size, size);

        return this._context.createPattern(tempCanvas, 'repeat')!;
    }

    private step(timestamp: number) {
        if (!this._active) {
            return;
        }

        const host = this;
        requestAnimationFrame((timestamp: number) => {
            host.step(timestamp);
        });

        if (!this._startTimestamp) {
            this._startTimestamp = timestamp;
        }

        const simLevel = this._simMain.currentLevel;
        let targetStep = (timestamp - this._startTimestamp) * this._simMain.gdRoot.simulation.stepsPerSecond / 1000 - this._gap;
        if (simLevel.paused) {
            this._gap += targetStep - simLevel.currentStep;
            targetStep = simLevel.currentStep;
        }
        this._simMain.executeUntilStep(targetStep);
        this._visLevel.updateEveryFrame(targetStep);
        this.onRender();
    };

    public onResized() {
        const gameHost = document.getElementById("game-host") as HTMLDivElement;
        const width = gameHost.clientWidth;
        const height = gameHost.clientHeight;
        const ratio = window.devicePixelRatio;
        this._canvas.width = width * ratio;
        this._canvas.height = height * ratio;
        this._canvas.style.width = width + "px";
        this._canvas.style.height = height + "px";
        this._context.scale(ratio, ratio);
        this._visLevel.updateSize();
    };

    private onRender() {
        this.clear();
        const ctx = this._context;
        ctx.font = "12px Tahoma";
        const simLevel = this._simMain.currentLevel;
        if (!!simLevel) {
            if (!this._ready) {
                this.onResized();
                this._ready = true;
            }
            this._visLevel.draw();
        }
    };

    private clear() {
        this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
    }

    private stop() {
        this._active = false;
    }
}
