// Copyright 2018-2026 the Deno authors. MIT license.

// deno-lint-ignore-file no-var

/// <reference no-default-lib="true" />
/// <reference lib="esnext" />

/**
 * Specifies whether the image should be decoded using color space conversion.
 * Either none or default (default). The value default indicates that
 * implementation-specific behavior is used.
 *
 * @category Canvas
 */
type ColorSpaceConversion = "default" | "none";

/**
 * Specifies how the bitmap image should be oriented.
 *
 * @category Canvas
 */
type ImageOrientation = "flipY" | "from-image" | "none";

/**
 * Specifies whether the bitmap's color channels should be premultiplied by
 * the alpha channel.
 *
 * @category Canvas
 */
type PremultiplyAlpha = "default" | "none" | "premultiply";

/**
 * Specifies the algorithm to be used for resizing the input to match the
 * output dimensions. One of `pixelated`, `low` (default), `medium`, or `high`.
 *
 * @category Canvas
 */
type ResizeQuality = "high" | "low" | "medium" | "pixelated";

/**
 * The `ImageBitmapSource` type represents an image data source that can be
 * used to create an `ImageBitmap`.
 *
 * @category Canvas */
type ImageBitmapSource = Blob | ImageData | ImageBitmap;

/**
 * The options of {@linkcode createImageBitmap}.
 *
 * @category Canvas */
interface ImageBitmapOptions {
  /**
   * Specifies whether the image should be decoded using color space
   * conversion. Either none or default (default). The value default
   * indicates that implementation-specific behavior is used.
   */
  colorSpaceConversion?: ColorSpaceConversion;
  /** Specifies how the bitmap image should be oriented. */
  imageOrientation?: ImageOrientation;
  /**
   * Specifies whether the bitmap's color channels should be premultiplied
   * by the alpha channel. One of none, premultiply, or default (default).
   */
  premultiplyAlpha?: PremultiplyAlpha;
  /** The output height. */
  resizeHeight?: number;
  /**
   * Specifies the algorithm to be used for resizing the input to match the
   * output dimensions. One of pixelated, low (default), medium, or high.
   */
  resizeQuality?: ResizeQuality;
  /** The output width. */
  resizeWidth?: number;
}

/**
 * Create a new {@linkcode ImageBitmap} object from a given source.
 *
 * @param image The image to create an {@linkcode ImageBitmap} from.
 * @param options The options for creating the {@linkcode ImageBitmap}.
 *
 * @category Canvas
 *
 * @example
 * ```ts
 * try {
 *   // Fetch an image
 *   const response = await fetch("https://example.com/image.png");
 *   const blob = await response.blob();
 *
 *   // Basic usage
 *   const basicBitmap = await createImageBitmap(blob);
 *   console.log("Basic bitmap size:", basicBitmap.width, basicBitmap.height);
 *
 *   // With options
 *   const resizedBitmap = await createImageBitmap(blob, {
 *     resizeWidth: 100,
 *     resizeHeight: 100,
 *     resizeQuality: "high",
 *     imageOrientation: "flipY"
 *   });
 *
 *   // Cleanup when done
 *   basicBitmap.close();
 *   resizedBitmap.close();
 * } catch (error) {
 *   console.error("Failed to create ImageBitmap:", error);
 * }
 * ```
 * @see https://developer.mozilla.org/en-US/docs/Web/API/createImageBitmap
 */
declare function createImageBitmap(
  image: ImageBitmapSource,
  options?: ImageBitmapOptions,
): Promise<ImageBitmap>;
/**
 * Create a new {@linkcode ImageBitmap} object from a given source, cropping
 * to the specified rectangle.
 *
 * @param image The image to create an {@linkcode ImageBitmap} from.
 * @param sx The x coordinate of the top-left corner of the sub-rectangle from
 *           which the {@linkcode ImageBitmap} will be cropped.
 * @param sy The y coordinate of the top-left corner of the sub-rectangle from
 *           which the {@linkcode ImageBitmap} will be cropped.
 * @param sw The width of the sub-rectangle from which the
 *           {@linkcode ImageBitmap} will be cropped.
 * @param sh The height of the sub-rectangle from which the
 *           {@linkcode ImageBitmap} will be cropped.
 * @param options The options for creating the {@linkcode ImageBitmap}.
 *
 * @category Canvas
 *
 * @example
 * ```ts
 * try {
 *   // Fetch an image
 *   const response = await fetch("https://example.com/image.png");
 *   const blob = await response.blob();
 *
 *   // Cropping parameters
 *   const croppedBitmap = await createImageBitmap(
 *     blob,
 *     0,    // sx: start x
 *     0,    // sy: start y
 *     50,   // sw: source width
 *     50,   // sh: source height
 *   );
 *
 *   // Cleanup when done
 *   croppedBitmap.close();
 * } catch (error) {
 *   console.error("Failed to create ImageBitmap:", error);
 * }
 * ```
 * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/createImageBitmap
 */
declare function createImageBitmap(
  image: ImageBitmapSource,
  sx: number,
  sy: number,
  sw: number,
  sh: number,
  options?: ImageBitmapOptions,
): Promise<ImageBitmap>;

/**
 * `ImageBitmap` interface represents a bitmap image which can be drawn to a canvas.
 *
 * @category Canvas
 */
interface ImageBitmap {
  /**
   * The height of the bitmap.
   */
  readonly height: number;
  /**
   * The width of the bitmap.
   */
  readonly width: number;
  /**
   * Releases imageBitmap's resources.
   */
  close(): void;
}

/**
 * `ImageBitmap` represents a bitmap image which can be drawn to a canvas.
 *
 * @category Canvas
 */
declare var ImageBitmap: {
  prototype: ImageBitmap;
  new (): ImageBitmap;
};

/** @category Canvas */
type OffscreenRenderingContextId = "bitmaprenderer" | "webgpu";
/** @category Canvas */
type OffscreenRenderingContext = ImageBitmapRenderingContext | GPUCanvasContext;

/** @category Canvas */
interface ImageEncodeOptions {
  quality?: number;
  type?: string;
}

/** @category Canvas */
type GPUCanvasAlphaMode = "opaque" | "premultiplied";

/** @category Canvas */
type GPUPresentMode =
  | "auto-vsync"
  | "auto-no-vsync"
  | "fifo"
  | "fifo-relaxed"
  | "immediate"
  | "mailbox";

/** @category Canvas */
interface GPUCanvasConfiguration {
  device: GPUDevice;
  format: GPUTextureFormat;
  usage?: GPUTextureUsageFlags;
  viewFormats?: GPUTextureFormat[];
  colorSpace?: "srgb" | "display-p3";
  alphaMode?: GPUCanvasAlphaMode;

  // extended from spec
  presentMode?: GPUPresentMode;
}

/** The rendering context that presents WebGPU-rendered images on an
 * {@linkcode OffscreenCanvas}. Obtained from
 * {@linkcode OffscreenCanvas.getContext} with the `"webgpu"` context id.
 *
 * @category Canvas */
interface GPUCanvasContext {
  /** The canvas that this context is bound to. */
  readonly canvas: OffscreenCanvas;

  configure(configuration: GPUCanvasConfiguration): undefined;
  getConfiguration(): GPUCanvasConfiguration | null;
  unconfigure(): undefined;
  getCurrentTexture(): GPUTexture;
}
/** The constructor object for {@linkcode GPUCanvasContext}.
 *
 * A `GPUCanvasContext` is obtained from
 * {@linkcode OffscreenCanvas.getContext} with the `"webgpu"` context id rather
 * than constructed directly.
 *
 * @category Canvas */
declare var GPUCanvasContext: {
  prototype: GPUCanvasContext;
};

/** A rendering context that displays the contents of an {@linkcode ImageBitmap}
 * on an {@linkcode OffscreenCanvas}. Obtained from
 * {@linkcode OffscreenCanvas.getContext} with the `"bitmaprenderer"` context
 * id.
 *
 * @category Canvas */
interface ImageBitmapRenderingContext {
  /** The canvas that this context is bound to. */
  readonly canvas: OffscreenCanvas;

  transferFromImageBitmap(bitmap: ImageBitmap | null): undefined;
}
/** The constructor object for {@linkcode ImageBitmapRenderingContext}.
 *
 * An `ImageBitmapRenderingContext` is obtained from
 * {@linkcode OffscreenCanvas.getContext} with the `"bitmaprenderer"` context id
 * rather than constructed directly.
 *
 * @category Canvas */
declare var ImageBitmapRenderingContext: {
  prototype: ImageBitmapRenderingContext;
};

/** A canvas that can be rendered to off the main thread and without being
 * attached to the DOM. It exposes drawing contexts via
 * {@linkcode OffscreenCanvas.getContext} and can produce a {@linkcode Blob} or
 * {@linkcode ImageBitmap} from its contents.
 *
 * @category Canvas
 * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
 */
interface OffscreenCanvas extends EventTarget {
  /** The height of the canvas. */
  height: number;
  /** The width of the canvas. */
  width: number;

  /** Create a Blob object representing the image contained in the canvas. */
  convertToBlob(options?: ImageEncodeOptions): Promise<Blob>;

  /**
   * Get a drawing context for the canvas.
   * If this was previously called, it will return the same context.
   */
  getContext(
    contextId: "bitmaprenderer",
    options?: any,
  ): ImageBitmapRenderingContext | null;
  getContext(contextId: "webgpu", options?: any): GPUCanvasContext | null;
  getContext(
    contextId: OffscreenRenderingContextId,
    options?: any,
  ): OffscreenRenderingContext | null;
  // Spec also defines "2d", "webgl", and "webgl2" context ids; Deno does
  // not implement those and getContext returns null for them.
  getContext(
    contextId: "2d" | "webgl" | "webgl2",
    options?: any,
  ): null;

  /**
   * Create an ImageBitmap object representing the image contained in the canvas.
   */
  transferToImageBitmap(): ImageBitmap;
}

/** The constructor object for {@linkcode OffscreenCanvas}, used to create a new
 * offscreen canvas with the given `width` and `height` that can be rendered to
 * without being attached to the DOM.
 *
 * @category Canvas
 * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
 */
declare var OffscreenCanvas: {
  prototype: OffscreenCanvas;
  new (width: number, height: number): OffscreenCanvas;
};
