import * as core from "graphics-core";

/**
 * Clear the screen.
 *
 * @param r - The red component of the color to clear to, from 0 to 1.
 * @param g - The green component of the color to clear to, from 0 to 1.
 * @param b - The blue component of the color to clear to, from 0 to 1.
 */
export function cls(r: number, g: number, b: number) {
  core.cls(r, g, b);
}

/**
 * Set the current drawing color. This is the fill color for shapes that have
 * both stroke and fill.
 *
 * @param r - The red component of the color, from 0 to 1.
 * @param g - The green component of the color, from 0 to 1.
 * @param b - The blue component of the color, from 0 to 1.
 * @param a - The alpha (transparency) of the color, from 0 (transparent) to 1 (opaque)
 */
export function color(r: number, g: number, b: number, a: number = 1) {
  core.color(r, g, b, a);
}

/**
 * Set the current stroke color, for shapes that have a stroke.
 *
 * @param r - The red component of the color, from 0 to 1.
 * @param g - The green component of the color, from 0 to 1.
 * @param b - The blue component of the color, from 0 to 1.
 * @param a - The alpha (transparency) of the color, from 0 (transparent) to 1 (opaque)
 */
export function stroke(r: number, g: number, b: number, a: number = 1) {
  core.stroke(r, g, b, a);
}

/**
 * Set the current scale factor.
 *
 * @param x - The scale factor in the x dimension.
 * @param y - The scale factor in the y dimension. If omitted, defaults to x.
 */
export function scale(x: number, y?: number) {
  core.scale(x, y ?? x);
}

/**
 * Print a message to the console.
 *
 * @remarks
 * The specified arguments will be printed to the console, one at a time,
 * separated by spaces. If you want them separated by something else,
 * format the string yourself.
 *
 * @param x - The x coordinate of the upper-left corner of the text
 * @param y - The y coordinate of the upper-left corner of the text
 * @param args - Arguments to print to the console.
 */
export function print(x: number, y: number, ...args: unknown[]) {
  core.print(args.join(" "), x, y);
}

/**
 * Draw a sprite.
 *
 * @param x - The x coordinate of the upper-left pixel of the sprite.
 * @param y - The y coordinate of the upper-left pixel of the sprite.
 * @param w - The width of the target rectangle, in pixels.
 * @param h - The height of the target rectangle, in pixels.
 * @param sx - The x offset of the upper-left pixel of the sprite in the current sheet, in pixels.
 * @param sy - The y offset of the upper-left pixel of the sprite in the current sheet, in pixels.
 * @param sw - The width of the sprite, in pixels. If null or not specified, defaults to the width of the target rectangle.
 * @param sh - The height of the sprite, in pixels. If null or not specified, defaults to the height of the target rectangle.
 */
export function spr(
  x: number,
  y: number,
  w: number,
  h: number,
  sx: number,
  sy: number,
  sw: number | null = null,
  sh: number | null = null
) {
  sw = sw || w;
  sh = sh || h;
  core.spr(x, y, w, h, sx, sy, sw, sh);
}

/**
 * Draw a circle.
 *
 * @param x - The x coordinate of the center of the circle.
 * @param y - The y coordinate of the center of the circle.
 * @param r - The radius of the circle.
 * @param s - The stroke width of the circle.
 */
export function circle(x: number, y: number, r: number, s: number) {
  core.circle(x, y, r, s);
}

export class Texture {
  #id: number;
  constructor(id: number) {
    this.#id = id;
  }
  id(): number {
    return this.#id;
  }
}

/**
 * Create a texture based on the loaded buffer.
 *
 * @param buffer The underlying bytes that make up the texture image.
 * @param label The label to put onto the texture (for debugging).
 */
export function create_texture(
  buffer: ArrayBuffer,
  label: string | undefined = undefined
): Texture {
  const id = core.create_texture(buffer, label);
  return new Texture(id);
}

/**
 * Set the specified texture as the current texture for calls to e.g. spr().
 *
 * @param texture - The texture to use.
 */
export function use_texture(id: Texture) {
  core.use_texture(id.id());
}

/**
 * Create a texture that we can render to.
 */
export function create_writable_texture(
  width: number,
  height: number,
  label: string | undefined = undefined
): Texture {
  return new Texture(core.create_writable_texture(width, height, label));
}

/**
 * Set the current render target to the screen.
 */
export function write_to_screen() {
  core.write_to_screen();
}

/**
 * Set the current render target to the specified texture.
 */
export function write_to_texture(texture: Texture) {
  core.write_to_texture(texture.id());
}

/**
 * Get the dimensions of the screen.
 */
export function get_dimensions(): [number, number] {
  return core.get_dimensions();
}
