import { api } from "./client";

export interface PresignedUploadResponse {
  photo_id: number;
  presigned_url: string;
  fields: Record<string, string>;
  storage_key: string;
  expires_at: string;
}

export interface PhotoConfirmResponse {
  id: number;
  side: string;
  slot_index: number;
  storage_key: string;
  thumb_key?: string | null;
  annotated_key?: string | null;
  width?: number | null;
  height?: number | null;
  status: string;
  taken_at: string;
}

export async function uploadPhotoAnnotation(
  inspectionId: number,
  photoId: number,
  blob: Blob,
): Promise<PhotoConfirmResponse> {
  const form = new FormData();
  form.append("file", blob, "annotation.jpg");
  return api
    .post(`inspections/${inspectionId}/photos/${photoId}/annotation`, {
      body: form,
    })
    .json<PhotoConfirmResponse>();
}

export async function requestUploadUrl(
  inspectionId: number,
  args: { side: string; slot_index: number; content_type: string; size: number }
): Promise<PresignedUploadResponse> {
  return api
    .post(`inspections/${inspectionId}/photos/upload-url`, { json: args })
    .json<PresignedUploadResponse>();
}

/**
 * PUT the file directly to MinIO via the presigned URL.
 * Content-Type header MUST match the value the URL was signed with
 * (we pass the same `args.content_type` to requestUploadUrl).
 */
export async function uploadToS3(
  presigned: PresignedUploadResponse,
  file: File,
  contentType: string
): Promise<void> {
  const r = await fetch(presigned.presigned_url, {
    method: "PUT",
    headers: { "Content-Type": contentType },
    body: file,
  });
  if (!r.ok) {
    throw new Error(`S3 upload failed: ${r.status} ${r.statusText}`);
  }
}

export async function confirmPhoto(
  inspectionId: number,
  photoId: number,
  meta: { width?: number; height?: number; actual_size?: number }
): Promise<PhotoConfirmResponse> {
  return api
    .post(`inspections/${inspectionId}/photos/${photoId}/confirm`, { json: meta })
    .json<PhotoConfirmResponse>();
}

/**
 * Full upload flow: request URL → PUT to S3 → measure dims → confirm.
 * Returns the confirmed PhotoConfirmResponse (frontend uses .id mostly).
 */
export async function uploadPhoto(
  inspectionId: number,
  side: string,
  slotIndex: number,
  file: File
): Promise<PhotoConfirmResponse> {
  const contentType = file.type || "image/jpeg";

  const presign = await requestUploadUrl(inspectionId, {
    side,
    slot_index: slotIndex,
    content_type: contentType,
    size: file.size,
  });

  await uploadToS3(presign, file, contentType);

  // Measure dimensions from a local object URL (revoked once loaded).
  const dim = await new Promise<{ w: number; h: number }>((resolve, reject) => {
    const url = URL.createObjectURL(file);
    const img = new Image();
    img.onload = () => {
      const out = { w: img.naturalWidth, h: img.naturalHeight };
      URL.revokeObjectURL(url);
      resolve(out);
    };
    img.onerror = () => {
      URL.revokeObjectURL(url);
      reject(new Error("Could not read image dimensions"));
    };
    img.src = url;
  });

  return confirmPhoto(inspectionId, presign.photo_id, {
    width: dim.w,
    height: dim.h,
    actual_size: file.size,
  });
}
