/**
 * Build multipart FormData from encoded bundle and POST to /api/uploads/complete.
 * Server validates whitelist, conditional-puts to R2, returns { ok, sha256 }.
 * Moved from src/features/admin-deals/ to shared lib.
 */

import type { EncodedBundle } from './encodeImage';
import type { ImagePurpose } from '@/lib/imageVariants';
import { getCsrfToken } from '@/lib/csrf';
import { captureCaught } from '@/lib/observability';

export class UploadError extends Error {
  constructor(
    public readonly status: number,
    message: string,
  ) {
    super(message);
    this.name = 'UploadError';
  }
}

export interface UploadedImage {
  sha256: string;
  r2Key: string;
  url: string;
}

export async function uploadEncoded(
  bundle: EncodedBundle,
  purpose: ImagePurpose,
): Promise<UploadedImage> {
  const form = new FormData();
  form.append('sha256', bundle.sha256);
  form.append('purpose', purpose);
  form.append('original', bundle.original, 'original.jpg');
  for (const v of bundle.variants) {
    form.append(v.name, v.blob, v.name);
  }

  const headers: HeadersInit = {};
  const csrf = getCsrfToken();
  if (csrf) headers['x-csrf-token'] = csrf;

  const res = await fetch('/api/uploads/complete', {
    method: 'POST',
    body: form,
    headers,
    credentials: 'same-origin',
  });

  if (!res.ok) {
    const text = await res.text().catch((err: unknown) => {
      captureCaught(err, { scope: 'lib.image-upload.uploadImage' });
      return '';
    });
    throw new UploadError(res.status, text || `upload failed: ${res.status}`);
  }

  const json = (await res.json()) as { ok: boolean; sha256: string; r2Key?: string; url?: string };
  return {
    sha256: json.sha256,
    r2Key: json.r2Key ?? `originals/${json.sha256}.jpeg`,
    url: json.url ?? `/r2/originals/${json.sha256}.jpeg`,
  };
}
