import { createCanvas } from "@common/display/canvas";
import Spinner from "./spinner";
import type Entity from "./entity";
import { getRealPoint } from "@common/dom";
import { clamp, nextFrame } from "@common/utils";
import bgImg from './assets/bg.jpg';
import TileMap from "./tilemap";
import Inventory from "./inventory";

const MAP_SIZE = 12;
const MAP_PIXEL_SIZE = window.innerHeight;
const MAP_PADDING = 10;
const TILE_SIZE = (MAP_PIXEL_SIZE - MAP_PADDING * 2) / MAP_SIZE;
const SIDEBAR_SIZE = clamp((window.innerWidth - window.innerHeight) / 2, MAP_PADDING + 5 * TILE_SIZE, window.innerHeight / 2);

const canvas = createCanvas(MAP_PIXEL_SIZE + SIDEBAR_SIZE * 2, MAP_PIXEL_SIZE);

const spinner = new Spinner([MAP_PIXEL_SIZE + SIDEBAR_SIZE, 0], [SIDEBAR_SIZE, SIDEBAR_SIZE]);
const map = new TileMap(
    [MAP_PADDING + SIDEBAR_SIZE, MAP_PADDING],
    MAP_SIZE,
    TILE_SIZE,
    spinner,
);
const inventory = new Inventory(
    map,
    [0, 0],
    [SIDEBAR_SIZE, MAP_PIXEL_SIZE],
);

const entities: Entity[] = [
    spinner,
    map,
    inventory,
];

async function update(dt: number) {
    entities.forEach(entity => entity.update(dt));
}

async function render(ctx: CanvasRenderingContext2D) {
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';

    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    ctx.drawImage(bgImg, SIDEBAR_SIZE, 0, MAP_PIXEL_SIZE, MAP_PIXEL_SIZE);

    entities.forEach(entity => entity.render(ctx));
}

async function onClick(e: MouseEvent) {
    const point = getRealPoint(canvas, e);

    entities.forEach(entity => entity.handleClick(point.x, point.y));
}

async function onMouseMove(e: MouseEvent) {
    const point = getRealPoint(canvas, e);

    entities.forEach(entity => entity.handleMouseMove(point.x, point.y));
}

export default async function main() {
    canvas.style.imageRendering = 'auto';

    const ctx = canvas.getContext('2d');

    spinner.addListener((a) => map.handleSpin(a));

    canvas.addEventListener('click', onClick);
    canvas.addEventListener('mousemove', onMouseMove);

    if (ctx) {
        let prevFrame = performance.now();
        while (true) {
            const now = await nextFrame();
            const dt = (now - prevFrame) / 1000;
            prevFrame = now;

            update(dt);
            render(ctx);
        }
    }
}