import { TextRegion, TextDisplay } from "@common/display/text";
import { Position } from "@common/rpg/components/position";
import { Viewport } from "@common/rpg/components/render/viewport";
import { Hidden, Sprite } from "@common/rpg/components/sprite";
import { System, World } from "@common/rpg/core/world";
import { Resources } from "@common/rpg/utils/resources";

export class TextDisplaySystem extends System {
    public readonly display: TextDisplay;

    constructor(display: TextDisplay);
    constructor(width?: number, height?: number);
    constructor(displayOrWidth?: TextDisplay | number, height?: number) {
        super();
        this.display = displayOrWidth instanceof TextDisplay ? displayOrWidth : new TextDisplay(displayOrWidth, height);
    }

    override update(world: World) {
        const viewport = world.findComponent(Viewport);
        const offset = viewport ? viewport.screenToWorld({ x: 0, y: 0 }) : undefined;
        const viewportClipRect = viewport ? {
            x: viewport.screenX,
            y: viewport.screenY,
            width: viewport.width,
            height: viewport.height,
        } : undefined;

        const sprites = Array.from(world.query(Sprite, Position))
            .sort((a, b) => Number(a[2].absolute) - Number(b[2].absolute) || a[2].z - b[2].z);

        for (const [e, sprite, pos] of sprites) {
            if (e.has(Hidden)) continue;

            const image = sprite.image;
            const { x, y, absolute } = pos;

            const data =
                Resources.get(TextRegion, image)
                ?? Resources.get(String, image)
                ?? image;

            const region = data instanceof TextRegion ? data : new TextRegion(data);

            if (absolute || !offset || !viewportClipRect) {
                this.display.setRegion(x, y, region);
            } else {
                const clipRect = this.display.getClipRect();
                this.display.setClipRect(viewportClipRect);
                this.display.setRegion(x - offset.x, y - offset.y, region);
                this.display.setClipRect(clipRect);
            }
        }

        this.display.update();
    }
}