import recordAxiosInstance from "@/shared/services/recordAxiosInstance";
import { uploadFile } from "@/shared/services/fileService";
import axiosInstance from "@/shared/services/axiosInstance";

interface UploadKeyRequest {
  fileName: string;
  contentType: string;
  size: number;
  originalname: string;
}

export interface UploadKeyResponse {
  fileInfo: {
    bucket: string;
    fileName: string;
    contentType: string;
    originalname: string;
    size: number;
  };
  presigned: string;
}

export const STORAGE_UPLOAD_ERROR_CODE = "storage_upload_failed";
export const STORAGE_UPLOAD_TOO_LARGE = "storage_upload_too_large";

const isStorageUploadError = (error: any) =>
  error instanceof Error &&
  (error.message === STORAGE_UPLOAD_ERROR_CODE ||
    error.message === STORAGE_UPLOAD_TOO_LARGE);

const extractStatus = (error: unknown): number | undefined => {
  if (!error || typeof error !== "object") return undefined;
  const e = error as { status?: unknown; response?: { status?: unknown } };
  if (typeof e.status === "number") return e.status;
  if (typeof e.response?.status === "number") return e.response.status;
  return undefined;
};

export const recordFileServiceV2 = {
  // 🔹 Single file
  async getUploadKey(file: File): Promise<UploadKeyResponse> {
    const body = {
      fileName: file.name,
      contentType: file.type || "application/octet-stream",
      size: file.size,
      originalname: file.name,
    };

    const { data } = await recordAxiosInstance.post(
      "/record-attachments/get-file-upload-key",
      body,
    );

    return data;
  },
  async getUploadKeySiteSetting(file: File): Promise<UploadKeyResponse> {
    const body = {
      fileName: file.name,
      contentType: file.type || "application/octet-stream",
      size: file.size,
      originalname: file.name,
    };

    const { data } = await axiosInstance.post(
      "/site-settings/get-file-upload-key",
      body,
    );

    return data;
  },

  // 🔹 Multiple files
  async getMultipleUploadKeys(files: File[]): Promise<UploadKeyResponse[]> {
    const body = files.map((file) => ({
      fileName: file.name,
      contentType: file.type || "application/octet-stream",
      size: file.size,
      originalname: file.name,
    }));

    const { data } = await recordAxiosInstance.post(
      "/record-attachments/get-multiple-attachments-upload-key",
      body,
    );

    return data;
  },
  async getReplyUploadKeys(files: File[]): Promise<UploadKeyResponse[]> {
    // const body = files.map((file) => ({
    //   fileName: file.name as string,
    //   contentType: file.type || ("application/octet-stream" as string),
    //   size: file.size,
    //   originalname: file.name as string,
    // }));
    const body = {
      fileName: files[0].name,
      contentType: files[0].type || "application/octet-stream",
      size: files[0].size,
      originalname: files[0].name,
    };

    const { data } = await recordAxiosInstance.post(
      "/record-replies/upload-keys",
      body,
    );

    return [data];
  },

  // 🔹 Upload using presigned URL
  async uploadToPresigned(file: File, presignedUrl: string) {
    try {
      return await uploadFile(file, presignedUrl);
    } catch (error) {
      console.error(`Presigned upload failed for ${file.name}:`, error);
      // S3 returns 413 when the upload exceeds the bucket / policy size limit.
      // Distinguish that from a generic transport failure so the UI can
      // append a "file too large" hint.
      if (extractStatus(error) === 413) {
        throw new Error(STORAGE_UPLOAD_TOO_LARGE);
      }
      throw new Error(STORAGE_UPLOAD_ERROR_CODE);
    }
  },
};

export const uploadSingle = async (file: File) => {
  try {
    // 1. Get upload key
    const { presigned, fileInfo } =
      await recordFileServiceV2.getUploadKey(file);

    // 2. Upload file
    await recordFileServiceV2.uploadToPresigned(file, presigned);

    // 3. Return fileInfo (IMPORTANT 🔥)
    return fileInfo;
  } catch (error: any) {
    console.error("Single file upload failed:", error);
    if (isStorageUploadError(error)) {
      throw error;
    }
    // Extract meaningful error message from axios response
    const errorMessage =
      error?.response?.data?.message ||
      error?.response?.data?.exception?.response?.message ||
      error?.message ||
      error;
    throw new Error(`Failed to upload file ${file.name}: ${errorMessage}`);
  }
};
export const uploadSingleBranding = async (file: File) => {
  try {
    // 1. Get upload key
    const { presigned, fileInfo } =
      await recordFileServiceV2.getUploadKeySiteSetting(file);

    // 2. Upload file
    await recordFileServiceV2.uploadToPresigned(file, presigned);

    // 3. Return fileInfo (IMPORTANT 🔥)
    return { presigned, fileInfo };
  } catch (error: any) {
    console.error("Single file upload failed:", error);
    if (isStorageUploadError(error)) {
      throw error;
    }
    // Extract meaningful error message from axios response
    const errorMessage =
      error?.response?.data?.message ||
      error?.response?.data?.exception?.response?.message ||
      error?.message ||
      error;
    throw new Error(`Failed to upload file ${file.name}: ${errorMessage}`);
  }
};

export const uploadMultiple = async (files: File[]) => {
  try {
    const responses = await recordFileServiceV2.getMultipleUploadKeys(files);

    // 1. Upload all files
    await Promise.all(
      responses.map((res, index) =>
        recordFileServiceV2.uploadToPresigned(files[index], res.presigned),
      ),
    ); // 2. Return fileInfos for record creation
    return responses.map((r) => r.fileInfo);
  } catch (error: any) {
    console.error("Multiple file upload failed:", error);
    if (isStorageUploadError(error)) {
      throw error;
    }
    // Extract meaningful error message from axios response
    const errorMessage =
      error?.response?.data?.message ||
      error?.response?.data?.exception?.response?.message ||
      error?.message ||
      error;
    throw new Error(`Failed to upload multiple files: ${errorMessage}`);
  }
};
export const uploadReplies = async (files: File[]) => {
  try {
    const responses = await recordFileServiceV2.getReplyUploadKeys(files);
    if (files.length !== responses.length) {
      throw new Error("Mismatch between files and upload keys received");
    }
    if (files.length > 1) {
      await Promise.all(
        responses.map((res, index) =>
          recordFileServiceV2.uploadToPresigned(files[index], res.presigned),
        ),
      );
      return responses.map((r) => r.fileInfo);
    } else if (files.length === 1) {
      await recordFileServiceV2.uploadToPresigned(
        files[0],
        responses[0].presigned,
      );
      return responses[0].fileInfo;
    }

    const { presigned, fileInfo } = await recordFileServiceV2.getUploadKey(
      files[0],
    );

    // 2. Upload file
    await recordFileServiceV2.uploadToPresigned(files[0], presigned);

    // 3. Return fileInfo (IMPORTANT 🔥)
    return fileInfo;
  } catch (error: any) {
    const errorMessage =
      error?.response?.data?.message ||
      error?.response?.data?.exception?.response?.message ||
      error?.message ||
      error;
    throw new Error(`Failed to upload multiple files: ${errorMessage}`);
  }
};
