/**
 * Shrinks a receipt photo in the browser before upload so the server does not
 * have to ingest a 5–10 MB iPhone original. PDFs and images that already fit
 * the budget are returned unchanged. HEIC that the browser cannot decode is
 * left as-is — the server converts it.
 */

import { AI_IMAGE_MIN_WIDTH_PX, computeReceiptResize } from "./resize";

// 2048px/700KB was fast, but on a full-table phone photo the receipt itself
// can occupy less than a quarter of the width. Preserve enough source pixels
// for the server-side crop before creating OCR detail views, while still
// keeping uploads far below the 10MB API limit.
export const CLIENT_UPLOAD_LONG_EDGE_PX = 3072;
export const CLIENT_UPLOAD_MAX_BYTES = 1536 * 1024;
export const CLIENT_UPLOAD_SKIP_BELOW_BYTES = 600 * 1024;
export const CLIENT_UPLOAD_MIN_WIDTH_PX = AI_IMAGE_MIN_WIDTH_PX;

function isPdfFile(file: File): boolean {
  return file.type === "application/pdf" || file.name.toLowerCase().endsWith(".pdf");
}

function jpegFileName(name: string): string {
  return name.replace(/\.(heic|heif|png|webp|jpeg|jpg)$/i, "") + ".jpg";
}

async function canvasToJpegBlob(canvas: HTMLCanvasElement, quality: number): Promise<Blob> {
  return new Promise((resolve, reject) => {
    canvas.toBlob(
      (blob) => {
        if (!blob) reject(new Error("canvas.toBlob returned null"));
        else resolve(blob);
      },
      "image/jpeg",
      quality
    );
  });
}

/**
 * Downscales and recompresses an image File for `/api/scan`.
 * Safe to call from the dashboard or the landing page.
 */
export async function prepareUploadFile(file: File): Promise<File> {
  if (typeof window === "undefined") return file;
  if (isPdfFile(file)) return file;
  if (file.size > 0 && file.size <= CLIENT_UPLOAD_SKIP_BELOW_BYTES) return file;

  let bitmap: ImageBitmap;
  try {
    bitmap = await createImageBitmap(file);
  } catch {
    return file;
  }

  try {
    const { width, height } = computeReceiptResize(bitmap.width, bitmap.height, {
      defaultLongEdge: CLIENT_UPLOAD_LONG_EDGE_PX,
      minWidth: CLIENT_UPLOAD_MIN_WIDTH_PX,
      maxLongEdge: 4096,
      allowUpscale: false,
    });
    if (width === bitmap.width && height === bitmap.height && file.size <= CLIENT_UPLOAD_MAX_BYTES) {
      return file;
    }

    const canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext("2d");
    if (!ctx) return file;
    ctx.fillStyle = "#ffffff";
    ctx.fillRect(0, 0, width, height);
    ctx.drawImage(bitmap, 0, 0, width, height);

    let quality = 0.88;
    let blob = await canvasToJpegBlob(canvas, quality);
    while (blob.size > CLIENT_UPLOAD_MAX_BYTES && quality > 0.72) {
      quality = Math.round((quality - 0.08) * 100) / 100;
      blob = await canvasToJpegBlob(canvas, quality);
    }

    return new File([blob], jpegFileName(file.name), {
      type: "image/jpeg",
      lastModified: file.lastModified,
    });
  } catch {
    return file;
  } finally {
    bitmap.close();
  }
}
