import { onUnmounted, ref, type Ref } from 'vue';

import { message } from 'ant-design-vue';

export interface UsePasteUploadListenOptions {
  /** accept 字符串，如 `.jpg,.png,image/*,application/pdf`；支持 getter */
  accept?: string | (() => string);
  /** 单文件最大体积（字节）；支持 getter */
  maxSize?: number | (() => number);
  /** 过滤后的文件回调 */
  onFiles: (files: File[]) => void | Promise<void>;
  /**
   * 粘贴成功拿到合法文件后自动停止监听
   * 为什么默认 false：发票等组件仍要手动点「停止」；金方 Excel 导入需要成功即停
   */
  autoStopOnSuccess?: boolean;
}

/**
 * 将 accept 规则解析为便于匹配的片段列表
 */
function parseAccept(accept: string): string[] {
  return accept
    .split(',')
    .map((s) => s.trim().toLowerCase())
    .filter(Boolean);
}

/**
 * 判断文件是否匹配 accept（扩展名 / mime / image/* 等）
 */
export function matchAccept(file: File, accept: string): boolean {
  const rules = parseAccept(accept);
  if (!rules.length) return true;
  const name = (file.name || '').toLowerCase();
  const type = (file.type || '').toLowerCase();
  const ext = name.includes('.') ? `.${name.split('.').pop()}` : '';
  return rules.some((rule) => {
    if (rule === '*/*') return true;
    if (rule.endsWith('/*')) {
      const prefix = rule.slice(0, -1); // image/
      return type.startsWith(prefix);
    }
    if (rule.startsWith('.')) {
      return ext === rule;
    }
    return type === rule;
  });
}

/**
 * 从粘贴事件中收集 File（files + items 截图等）
 */
export function collectPasteFiles(event: ClipboardEvent): File[] {
  const result: File[] = [];
  const seen = new Set<string>();
  const push = (file: File | null | undefined) => {
    if (!file) return;
    const key = `${file.name}|${file.size}|${file.type}|${file.lastModified}`;
    if (seen.has(key)) return;
    seen.add(key);
    result.push(file);
  };

  const files = event.clipboardData?.files;
  if (files?.length) {
    for (let i = 0; i < files.length; i++) {
      push(files.item(i));
    }
  }

  const items = event.clipboardData?.items;
  if (items?.length) {
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      if (item?.kind === 'file') {
        push(item.getAsFile());
      }
    }
  }
  return result;
}

/**
 * 开始/停止监听窗口粘贴，用于上传组件在拖拽区外主动开启粘贴上传
 */
export function usePasteUploadListen(options: UsePasteUploadListenOptions) {
  const listening: Ref<boolean> = ref(false);
  let handler: ((e: ClipboardEvent) => void) | null = null;

  function stop() {
    if (handler) {
      window.removeEventListener('paste', handler);
      handler = null;
    }
    listening.value = false;
  }

  function start() {
    stop();
    handler = (event: ClipboardEvent) => {
      const acceptRaw = options.accept;
      const accept =
        typeof acceptRaw === 'function' ? acceptRaw() : acceptRaw || '';
      const maxSizeRaw = options.maxSize;
      const maxSize =
        typeof maxSizeRaw === 'function'
          ? maxSizeRaw()
          : (maxSizeRaw ?? 20 * 1024 * 1024);
      const raw = collectPasteFiles(event);
      if (!raw.length) {
        message.warning('剪贴板中没有可上传的文件');
        return;
      }
      const filtered: File[] = [];
      for (const file of raw) {
        if (accept && !matchAccept(file, accept)) {
          continue;
        }
        if (file.size > maxSize) {
          message.warning(`${file.name || '文件'} 超过大小限制`);
          continue;
        }
        // 截图常无名为空，补一个默认名便于上传
        if (!file.name) {
          const ext =
            file.type === 'image/png'
              ? 'png'
              : file.type === 'image/jpeg'
                ? 'jpg'
                : file.type === 'application/pdf'
                  ? 'pdf'
                  : 'bin';
          filtered.push(new File([file], `paste-${Date.now()}.${ext}`, { type: file.type }));
        } else {
          filtered.push(file);
        }
      }
      if (!filtered.length) {
        message.warning('剪贴板文件类型不符合要求');
        return;
      }
      event.preventDefault();
      // 成功拿到文件后先停监听（按需），再回调业务，避免重复粘贴
      if (options.autoStopOnSuccess) {
        stop();
        message.success('已粘贴文件，监听已结束');
      }
      void options.onFiles(filtered);
    };
    window.addEventListener('paste', handler);
    listening.value = true;
  }

  function toggle() {
    if (listening.value) stop();
    else start();
  }

  onUnmounted(() => {
    stop();
  });

  return {
    listening,
    start,
    stop,
    toggle,
  };
}
