// A 3D GPU texture, decoded natively by creator-gl. Load from a URL or an already-fetched response.

import { fetch, type FetchResponse, type File } from "../runtime/fetch"

export class Texture {
  /** @internal native texture handle. */
  readonly _id: number
  readonly width: number
  readonly height: number

  /** Horizontal wrap mode (U). */
  wrapS = 1
  /** Vertical wrap mode (V). */
  wrapT = 1

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

  // Wrap a Canvas's baked surface as a 3D texture (RGBA8, already rasterized → synchronous, no decode).
  // The id is cached on the canvas (opaque _tex3dId), so backing several materials shares one texture and
  // canvas.update() re-uploads it. Structural type avoids a Canvas import (keeps 3D free of 2D-canvas code).
  static fromCanvas(canvas: { _bakeSurface(): number, width: number, height: number, pixelRatio: number, _tex3dId: number }): Texture {
    if (!canvas._tex3dId) {
      const surfaceId = canvas._bakeSurface()
      canvas._tex3dId = _creator.createTextureFromCanvas(surfaceId)
    }
    return new Texture(Math.round(canvas.width * canvas.pixelRatio), Math.round(canvas.height * canvas.pixelRatio), canvas._tex3dId)
  }

  static load(source: string | FetchResponse | File): Promise<Texture> {
    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 Texture.load(resp)
      })
    }
    return new Promise<Texture>((resolve, reject) => {
      _creator.createTexture((source as any)._id, (id, w, h) => resolve(new Texture(w, h, id)), reject)
    })
  }
}
