import axios from "axios";
import api from "@/lib/api/axios";
import {
  UPLOAD_RULES,
  UploadType,
  type PresignUploadRequest,
  type PresignUploadResponse,
  type UploadRejectionReason,
} from "@/types/upload";

/**
 * Ask the backend for a temporary presigned PUT URL. Public for the provider
 * logo/document upload types, so it works before the user has an account.
 */
export async function presignUploadApi(
  payload: PresignUploadRequest,
): Promise<PresignUploadResponse> {
  const { data } = await api.post<PresignUploadResponse>(
    "/uploads/presign",
    payload,
  );
  return data;
}

/**
 * PUT the raw bytes straight to the presigned URL.
 *
 * Deliberately uses a bare `axios` call, NOT the shared `api` instance: the `api`
 * request interceptor would attach an `Authorization` bearer and an `x-language`
 * header, while the presigned URL already carries its own SigV4 auth in the query
 * string. The `Content-Type` MUST equal the mimeType that was presigned or
 * S3/MinIO rejects it with SignatureDoesNotMatch.
 */
export async function putFileToPresignedUrl(
  uploadUrl: string,
  file: File,
  onProgress?: (percent: number) => void,
): Promise<void> {
  await axios.put(uploadUrl, file, {
    headers: { "Content-Type": file.type },
    onUploadProgress: (event) => {
      if (onProgress && event.total) {
        onProgress(Math.round((event.loaded / event.total) * 100));
      }
    },
  });
}

/**
 * Client-side pre-check mirroring backend `UPLOAD_RULES`. Returns `null` when the
 * file is acceptable, otherwise a reason the caller maps to localized copy.
 */
export function validateUploadFile(
  file: File,
  uploadType: UploadType,
): UploadRejectionReason | null {
  const rules = UPLOAD_RULES[uploadType];
  if (file.size > rules.maxSize) return "too-large";
  if (!rules.allowedMimeTypes.includes(file.type)) return "invalid-type";
  return null;
}

/**
 * One-shot: presign → PUT → return the temporary s3Key.
 * Assumes the file has already passed {@link validateUploadFile}.
 */
export async function uploadFileToStorage(
  file: File,
  uploadType: UploadType,
  onProgress?: (percent: number) => void,
): Promise<string> {
  const { uploadUrl, s3Key } = await presignUploadApi({
    fileName: file.name,
    mimeType: file.type,
    fileSize: file.size,
    uploadType,
  });
  await putFileToPresignedUrl(uploadUrl, file, onProgress);
  return s3Key;
}
