// A GPU texture decoded natively by creator-2d (stb_image). Load from a URL (or an already-fetched
// response); the raw file bytes are handed to the engine, which decodes + uploads them.

// Internal SDK code imports injected globals explicitly (the bare-global inject is only for USER
// code; here `fetch` would otherwise resolve to the node/bun ambient one).
import { fetch, type FetchResponse, type File } from "../runtime/fetch"

export class Texture2D {
  /** Native texture handle. */
  readonly id: number
  readonly width: number
  readonly height: number

  constructor(id: number, width: number, height: number) {
    this.id = id
    this.width = width
    this.height = height
  }

  // Wrap a Canvas's baked surface as a texture (RGBA8, already rasterized → synchronous, no decode).
  // Structural type avoids a Canvas import cycle (Canvas imports Texture2D).
  static fromCanvas(canvas: { _bakeSurface(): number, width: number, height: number, pixelRatio: number }): Texture2D {
    const surfaceId = canvas._bakeSurface()
    const texId = _creator2d.createTextureFromCanvas(surfaceId)
    return new Texture2D(texId, Math.round(canvas.width * canvas.pixelRatio), Math.round(canvas.height * canvas.pixelRatio))
  }

  // Accepts a URL, an already-fetched response, or a File (e.g. from Canvas.toFile() / openFilePicker) —
  // anything backed by a host buffer. The buffer's encoded bytes are decoded + uploaded by the engine.
  static load(source: string | FetchResponse | File): Promise<Texture2D> {
    if (typeof source === "string") {
      return fetch(source, { useOnce: true }).then((resp) => {
        if (resp.status >= 400) {
          return Promise.reject(new Error(`Failed to fetch texture from ${source}. HTTP ${resp.status}`))
        }
        return Texture2D.load(resp)
      })
    }
    return new Promise<Texture2D>((resolve, reject) => {
      _creator2d.createTexture((source as any).id ?? (source as any)._id, (id, w, h) => resolve(new Texture2D(id, w, h)), reject)
    })
  }

  destroy(): void {
    _creator2d.destroyTexture(this.id)
  }
}
