/** Center-crop + downscale helpers for character portraits / token icons.
 *  Kept tiny so portraits stay cheap in IndexedDB and over the wire. */

/** Source rect for a centered square crop of a WxH image. */
export function coverCrop(w: number, h: number): { sx: number; sy: number; s: number } {
  const s = Math.max(0, Math.min(w, h));
  return { sx: (w - s) / 2, sy: (h - s) / 2, s };
}

function loadImage(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  });
}

/** Downscale an image to fit within maxDim (preserving aspect), as a JPEG data URL. */
export async function resizeToMax(src: string, maxDim = 1024, quality = 0.85): Promise<string> {
  try {
    const img = await loadImage(src);
    const scale = Math.min(1, maxDim / Math.max(img.naturalWidth, img.naturalHeight));
    const w = Math.max(1, Math.round(img.naturalWidth * scale));
    const h = Math.max(1, Math.round(img.naturalHeight * scale));
    const canvas = document.createElement('canvas');
    canvas.width = w; canvas.height = h;
    const ctx = canvas.getContext('2d');
    if (!ctx) return src;
    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';
    ctx.drawImage(img, 0, 0, w, h);
    return canvas.toDataURL('image/jpeg', quality);
  } catch {
    return src;
  }
}

/** Natural pixel size of an image data URL. */
export function imageSize(src: string): Promise<{ w: number; h: number }> {
  return loadImage(src).then((img) => ({ w: img.naturalWidth, h: img.naturalHeight }));
}

/** Read a File as a data URL. */
export function fileToDataUrl(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result));
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

/**
 * Load an image (data URL or object URL), center-crop to a square and downscale
 * to `size`px, returning a compact JPEG data URL. Falls back to the source on
 * any failure so callers never end up with nothing.
 */
export async function squareThumbnail(src: string, size = 160, quality = 0.82): Promise<string> {
  try {
    const img = await loadImage(src);
    const { sx, sy, s } = coverCrop(img.naturalWidth, img.naturalHeight);
    if (s <= 0) return src;
    const canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext('2d');
    if (!ctx) return src;
    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';
    ctx.drawImage(img, sx, sy, s, s, 0, 0, size, size);
    return canvas.toDataURL('image/jpeg', quality);
  } catch {
    return src;
  }
}
