export type ImageUploadPurpose =
  | "avatar"
  | "profile"
  | "olympiadProfile"
  | "generatedImage";

interface PresignedPostResponse {
  url: string;
  fields: Record<string, string>;
  publicUrl: string;
}

const MAX_IMAGE_SIZE_BYTES = 2.5 * 1024 * 1024;
const ALLOWED_IMAGE_TYPES = ["image/jpeg", "image/png", "image/webp"];

export async function uploadImageToS3(
  file: File,
  purpose: ImageUploadPurpose = "profile",
) {
  if (!ALLOWED_IMAGE_TYPES.includes(file.type)) {
    throw new Error("Only JPG, PNG and WEBP images are allowed.");
  }

  if (file.size > MAX_IMAGE_SIZE_BYTES) {
    throw new Error("Please upload image under 2.5MB");
  }

  const token =
    typeof window !== "undefined" ? localStorage.getItem("token") : null;

  const response = await fetch("/api/uploads/s3-presigned-post", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    body: JSON.stringify({
      contentType: file.type,
      fileSize: file.size,
      purpose,
    }),
  });

  const data = (await response.json()) as Partial<PresignedPostResponse> & {
    message?: string;
  };

  if (!response.ok || !data.url || !data.fields || !data.publicUrl) {
    throw new Error(data.message || "Unable to prepare image upload.");
  }

  const formData = new FormData();
  Object.entries(data.fields).forEach(([key, value]) => {
    formData.append(key, value);
  });
  formData.append("file", file);

  const uploadResponse = await fetch(data.url, {
    method: "POST",
    body: formData,
  });

  if (!uploadResponse.ok) {
    throw new Error("Image upload failed. Please try again.");
  }

  return data.publicUrl;
}
