import { CollageModes } from "../src/common/collages.ts";
import {
  CanvasRenderingContext2D,
  EmulatedCanvas2D,
  Image,
} from "https://deno.land/x/canvas/mod.ts";
import {
  CollageImage,
} from "../src/common/types.ts";
import { init } from "https://deno.land/x/canvas@v1.3.0/mod.ts";

const canvasKit = await init();

export class ProxyImage implements CollageImage {
  private filepath: string | null;
  private _image: Image | undefined;

  constructor(input: string | Image) {
    if (typeof input === "string") {
      this.filepath = input;
    } else {
      this.filepath = null;
      this._image = input;
    }
  }

  public get image(): Image {
    if (!this._image) {
      const image = canvasKit.MakeImageFromEncoded(
        Deno.readFileSync(this.filepath!),
      );
      if (!image) {
        throw Error(`Failed loading ${this.filepath}!`);
      }
      this._image = image;
    }
    return this._image;
  }

  public get width(): number {
    return this.image.width();
  }

  public get height(): number {
    return this.image.height();
  }
}

declare module "https://deno.land/x/canvas/mod.ts" {
  interface HTMLCanvasElement {
    width: number;
    height: number;
    getContext(x: '2d'): CanvasRenderingContext2D
  }
}

export class DenoCollageModes
  extends CollageModes<
  CanvasRenderingContext2D,
  ProxyImage,
  EmulatedCanvas2D
  > {

  createCanvas(w: number, h: number): EmulatedCanvas2D {
    const canvas = canvasKit.MakeCanvas(Math.round(w), Math.round(h));
    if (!canvas) {
      throw Error("Error initializing canvas.");
    }
    return canvas;
  }

  canvasToImage(canvas: EmulatedCanvas2D): PromiseLike<ProxyImage> {
    const image = canvasKit.MakeImageFromEncoded(
      canvas.toBuffer(),
    );
    if (!image) {
      throw Error("Something went wrong converting canvas to image.");
    }
    return Promise.resolve(new ProxyImage(image));
  }

  drawImage(
    ctx: CanvasRenderingContext2D,
    image: ProxyImage,
    sx: number,
    sy: number,
    sw: number,
    sh: number,
    dx: number,
    dy: number,
    dw: number,
    dh: number,
  ): void {
    ctx.drawImage(image.image, sx, sy, sw, sh, dx, dy, dw, dh);
  }
}

export const denoCollageModes = new DenoCollageModes();
