import api from "../axios";
import { buildFileDownloadUrl } from "../config";
import { API_ENDPOINTS } from "../endpoints";
import { BatchUploadResult, FileInfo } from "../types";

interface IUploadFileParams {
  file: File;
  category?: string;
  tags?: string[];
  description?: string;
  onProgress?: (percent: number) => void;
}

interface IUploadBatchParams {
  files: File[];
  category?: string;
  tags?: string[];
  description?: string;
  onProgress?: (percent: number) => void;
}

const trackUploadProgress =
  (onProgress?: (percent: number) => void) =>
  (progressEvent: { loaded: number; total?: number }) => {
    if (!progressEvent.total) return;
    onProgress?.(
      Math.round((progressEvent.loaded * 100) / progressEvent.total),
    );
  };

export const fileService = {
  /**
   * Uploads a binary file to the shared filestore endpoint and returns the
   * absolute, directly-loadable download URL for the stored file.
   *
   * Mirrors the two-step flow documented for CMS/marketing media: upload the
   * file, then persist the resulting URL on the entity (e.g. `card.icon`).
   */
  uploadFile: async ({
    file,
    category,
    tags = [],
    description,
    onProgress,
  }: IUploadFileParams): Promise<string> => {
    try {
      const formData = new FormData();
      formData.append("file", file);
      if (category) formData.append("category", category);
      tags.forEach((tag) => formData.append("tags", tag));
      if (description) formData.append("description", description);

      const response = await api.post(API_ENDPOINTS.FILES.UPLOAD, formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
        onUploadProgress: trackUploadProgress(onProgress),
      });

      const fileId = response?.data?.file_id as string | undefined;
      if (!fileId) {
        throw new Error("No file id returned from upload");
      }

      return buildFileDownloadUrl(fileId);
    } catch (error) {
      console.error("ERROR caught in File Service Upload File", error);
      throw error;
    }
  },

  /**
   * Uploads multiple files in one request. Returns the batch body directly
   * (this endpoint is not wrapped in the `success`/`data` envelope).
   */
  uploadBatch: async ({
    files,
    category,
    tags = [],
    description,
    onProgress,
  }: IUploadBatchParams): Promise<BatchUploadResult> => {
    try {
      const formData = new FormData();
      files.forEach((file) => formData.append("files", file, file.name));
      if (category) formData.append("category", category);
      tags.forEach((tag) => formData.append("tags", tag));
      if (description) formData.append("description", description);

      const response = await api.post(
        API_ENDPOINTS.FILES.UPLOAD_BATCH,
        formData,
        {
          headers: { "Content-Type": "multipart/form-data" },
          onUploadProgress: trackUploadProgress(onProgress),
        },
      );

      return response.data as BatchUploadResult;
    } catch (error) {
      console.error("ERROR caught in File Service Upload Batch", error);
      throw error;
    }
  },

  /** Normalized metadata for a stored file, tolerant of envelope/key variations. */
  getFileInfo: async (fileId: string): Promise<FileInfo> => {
    try {
      const response = await api.get(API_ENDPOINTS.FILES.INFO(fileId));
      const info = response.data?.data ?? response.data ?? {};

      return {
        file_id: fileId,
        filename: info.filename ?? info.name ?? "Document",
        content_type: info.content_type ?? info.contentType ?? "",
        size: Number(info.size ?? info.length ?? 0),
      };
    } catch (error) {
      console.error("ERROR caught in File Service Get File Info", error);
      throw error;
    }
  },

  /** Downloads a stored file as a blob (caller saves it). */
  downloadFile: (fileId: string) =>
    api.get<Blob>(API_ENDPOINTS.FILES.DOWNLOAD(fileId), {
      responseType: "blob",
    }),

  /** Permanently removes a file from storage. */
  deleteFile: async (fileId: string) => {
    try {
      return (await api.delete(API_ENDPOINTS.FILES.DELETE(fileId))).data;
    } catch (error) {
      console.error("ERROR caught in File Service Delete File", error);
      throw error;
    }
  },
};
