import { getScreen } from "./screen.ts";
import { AlignX, AlignY, Color, Point, Size } from "../datatypes.ts";
import { mainFont } from "./font.ts";
import { Sprite } from "./sprite.ts";

class Drawing {
  camera: Point;

  constructor() {
    this.camera = new Point(0, 0);
  }

  withCamera(point: Point, cb: () => void) {
    let oldCamera = this.camera;
    this.camera = this.camera = point;

    cb();

    this.camera = oldCamera;
  }

  get size() {
    return getScreen().size;
  }

  invertRect(position: Point, size: Size) {
    position = this.camera.negate().offset(position);

    let ctx = getScreen().unsafeMakeContext();
    ctx.globalCompositeOperation = "difference";
    ctx.fillStyle = "#fff";
    ctx.fillRect(
      Math.floor(position.x),
      Math.floor(position.y),
      Math.floor(size.w),
      Math.floor(size.h),
    );
  }

  fillRect(position: Point, size: Size, color: Color) {
    position = this.camera.negate().offset(position);

    let ctx = getScreen().unsafeMakeContext();
    ctx.fillStyle = color.toStyle();
    ctx.fillRect(
      Math.floor(position.x),
      Math.floor(position.y),
      Math.floor(size.w),
      Math.floor(size.h),
    );
  }

  drawRect(position: Point, size: Size, color: Color) {
    position = this.camera.negate().offset(position);

    let ctx = getScreen().unsafeMakeContext();
    ctx.strokeStyle = color.toStyle();
    ctx.strokeRect(
      Math.floor(position.x) + 0.5,
      Math.floor(position.y) + 0.5,
      Math.floor(size.w) - 1,
      Math.floor(size.h) - 1,
    );
  }

  drawText(
    text: string,
    position: Point,
    color: Color,
    options?: { alignX?: AlignX; alignY?: AlignY; forceWidth?: number },
  ) {
    position = this.camera.negate().offset(position);

    let ctx = getScreen().unsafeMakeContext();
    mainFont.internalDrawText({
      ctx,
      text,
      position,
      alignX: options?.alignX,
      alignY: options?.alignY,
      forceWidth: options?.forceWidth,
      color,
    });
  }

  measureText(text: string, forceWidth?: number): Size {
    return mainFont.measureText({ text, forceWidth });
  }

  drawSprite(
    sprite: Sprite,
    position: Point,
    ix?: number,
    options?: { xScale?: number; yScale?: number; angle?: number },
  ) {
    position = this.camera.negate().offset(position);

    let ctx = getScreen().unsafeMakeContext();
    sprite.internalDraw(ctx, {
      position,
      ix,
      xScale: options?.xScale,
      yScale: options?.yScale,
      angle: options?.angle,
    });
  }
}

let active: Drawing = new Drawing();

export function getDrawing(): Drawing {
  return active;
}