import { http } from "./index";
import axios from "axios";
import { buildOssDirPath } from "@/utils/env";

/** 上传请求 AbortController 映射，用于取消上传 */
const uploadControllers = new Map<string, AbortController>();

export interface UploadResult {
  success: boolean;
  filePath: string;
  fileName: string;
  originalName: string;
  fileSize: number;
  mimeType: string;
}

export interface DeleteResult {
  success: boolean;
  message: string;
}

/**
 * 获取指定文件的 AbortController（用于取消上传）
 */
export function getUploadController(file: File): AbortController {
  const key = `${file.name}_${file.size}_${file.lastModified}`;
  let controller = uploadControllers.get(key);
  if (!controller) {
    controller = new AbortController();
    uploadControllers.set(key, controller);
  }
  return controller;
}

/**
 * 取消指定文件的上传
 */
export function abortUpload(file: File): void {
  const key = `${file.name}_${file.size}_${file.lastModified}`;
  const controller = uploadControllers.get(key);
  if (controller) {
    controller.abort();
    uploadControllers.delete(key);
  }
}

/**
 * 取消所有进行中的上传
 */
export function abortAllUploads(): void {
  uploadControllers.forEach((controller) => controller.abort());
  uploadControllers.clear();
}

/**
 * OSS 直传 Token 响应
 */
export interface OssToken {
  accessid: string;
  policy: string;
  signature: string;
  dir: string;
  host: string;
  key: string;
  expire: number;
}

/**
 * 文件上传 API
 */
export const fileApi = {
  /**
   * 获取阿里云 OSS 直传 Token
   * 自动根据当前环境添加前缀（dev/test/prod）
   *
   * @param fileName 文件名
   * @param dir 业务目录（如：avatar, course/cover），会自动添加环境前缀
   * @returns OSS 直传 Token
   */
  getOssToken: async (fileName: string, dir?: string): Promise<OssToken> => {
    // 自动添加环境前缀
    const fullDir = buildOssDirPath(dir);

    const response = await http.get<OssToken>(`/v1/files/oss/token`, {
      params: { fileName, dir: fullDir },
    });
    console.log("getOssToken", response);
    return response;
  },

  /**
   * 直接上传文件到阿里云 OSS
   * 参考 uploadAliOSS 实现：支持取消、进度回调、超时
   *
   * @param file 文件
   * @param token OSS Token
   * @param options 进度回调函数（兼容旧 API）或配置对象 { onProgress, signal, timeout }
   */
  uploadToOss: async (
    file: File,
    token: OssToken,
    options?:
      | ((percent: number) => void)
      | {
          onProgress?: (percent: number) => void;
          signal?: AbortSignal;
          timeout?: number;
        },
  ): Promise<{ url: string }> => {
    const opts =
      typeof options === "function" ? { onProgress: options } : (options ?? {});
    const formData = new FormData();

    // 按照阿里云 OSS PostObject 要求构造表单
    formData.append("success_action_status", "200"); // 成功时返回 200
    formData.append("OSSAccessKeyId", token.accessid);
    formData.append("policy", token.policy);
    formData.append("signature", token.signature);
    formData.append("key", token.key);
    formData.append("x-oss-credential", token.accessid);
    formData.append("file", file); // file 必须为最后一个表单域

    const controller = getUploadController(file);
    const signal = opts.signal ?? controller.signal;
    console.log(token.host, formData, signal);
    try {
      await axios.post(token.host, formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
        timeout: opts.timeout ?? 1000 * 60 * 5, // 默认 5 分钟
        signal,
        onUploadProgress: (progressEvent) => {
          if (opts.onProgress) {
            const percent =
              progressEvent.progress != null
                ? progressEvent.progress * 100
                : progressEvent.total
                  ? (progressEvent.loaded * 100) / progressEvent.total
                  : 0;
            opts.onProgress(Math.round(percent));
          }
        },
      });
      return {
        url: `${token.host}/${token.key}`,
      };
    } catch (error) {
      console.error(error);
      throw error;
    } finally {
      abortUpload(file);
    }
  },
  /**
   * 上传文件（使用 OSS 直传方式）
   * 参考 uploadAliOSS：支持进度回调、取消上传
   *
   * @param file 要上传的文件
   * @param type 文件类型（用于指定 OSS 目录前缀）
   * @param options 可选：onProgress 进度回调、signal 取消信号、courseId 预留
   * @returns 上传结果，包含 OSS 文件 URL
   */
  uploadFile: async (
    file: File,
    type:
      | "cover"
      | "ebook"
      | "audio"
      | "video"
      | "ppt"
      | "poster"
      | "document"
      | "resource"
      | "other",
    options?: {
      onProgress?: (percent: number) => void;
      signal?: AbortSignal;
      courseId?: number;
    },
  ): Promise<UploadResult> => {
    // 1. 获取 OSS 直传 Token（自动添加环境前缀）
    const token = await fileApi.getOssToken(file.name, type);

    // 2. 上传到 OSS（支持进度、取消）
    await fileApi.uploadToOss(file, token, {
      onProgress: options?.onProgress,
      signal: options?.signal,
    });

    // 3. 返回兼容格式的结果
    return {
      success: true,
      filePath: `${token.host}/${token.key}`,
      fileName: file.name,
      originalName: file.name,
      fileSize: file.size,
      mimeType: file.type,
    };
  },

  /**
   * 删除文件
   */
  deleteFile: async (filePath: string): Promise<DeleteResult> => {
    const response = await http.post<DeleteResult>(`/v1/files/delete`, {
      filePath,
    });
    return response;
  },

  /**
   * 获取文件URL
   * 支持：完整 OSS URL、以 / 开头的路径、相对路径
   */
  getFileUrl: (filePath: string | null | undefined): string => {
    if (!filePath) return '';
    if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
      return filePath;
    }
    const SERVER_BASE = import.meta.env.VITE_SERVER_BASE_URL || '/api';
    if (filePath.startsWith('/')) {
      return `${SERVER_BASE}${filePath}`;
    }
    return `${SERVER_BASE}/uploads/${filePath}`;
  },
};

/**
 * 文件类型常量
 */
export const FILE_TYPES = {
  COVER: "cover",
  EBOOK: "ebook",
  AUDIO: "audio",
  VIDEO: "video",
  PPT: "ppt",
  POSTER: "poster",
  DOCUMENT: "document",
  RESOURCE: "resource",
  OTHER: "other",
} as const;

/**
 * 文件大小限制（字节）
 */
export const FILE_SIZE_LIMITS = {
  COVER: 10 * 1024 * 1024, // 10MB
  EBOOK: 300 * 1024 * 1024, // 300MB
  AUDIO: 300 * 1024 * 1024, // 300MB
  VIDEO: 300 * 1024 * 1024, // 300MB
  PPT: 300 * 1024 * 1024, // 300MB
  POSTER: 10 * 1024 * 1024, // 10MB
  DOCUMENT: 300 * 1024 * 1024, // 300MB
  RESOURCE: 100 * 1024 * 1024, // 100MB（资源库单文件限制）
  OTHER: 300 * 1024 * 1024, // 300MB
} as const;

/**
 * 每个分类最大文件数量
 */
export const MAX_FILE_COUNT = 15;

/**
 * 文件类型验证
 */
export const validateFileType = (
  file: File,
  type: keyof typeof FILE_SIZE_LIMITS,
): { valid: boolean; error?: string } => {
  const maxSize = FILE_SIZE_LIMITS[type];

  if (file.size > maxSize) {
    const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
    return {
      valid: false,
      error: `文件大小超过限制，最大允许 ${maxSizeMB}MB`,
    };
  }

  return { valid: true };
};

// 导出便捷函数
export const uploadFile = fileApi.uploadFile;
export const deleteFile = fileApi.deleteFile;
export const getFileUrl = fileApi.getFileUrl;
export const getOssToken = fileApi.getOssToken;
export const uploadToOss = fileApi.uploadToOss;
