/**
 * 文件下载
 * *将实时创建<a>标签并在下载完成后自动移除
 * @param url 文件地址
 * @param name 文件名
 */
export function downloadFile(url: string, name?: string): void {
  if (!url) return;
  const element = document.createElement('a');
  element.href = url;
  if (name) {
    element.download = name;
  }
  element.click();
  element.remove();
}

/**
 * 文件选择
 * @param accept 支持的文件类型
 * @param limit 文件大小限制（byte）
 * @returns 选中的文件域
 */
export async function selectFile(accept?: string, limit?: number): Promise<File | void> {
  const element = document.createElement('input');
  element.type = 'file';
  element.accept = accept ?? '';
  try {
    return await new Promise<File | void>((resolve, reject) => {
      element.onchange = () => {
        const file = element.files?.[0];
        if (!file?.size) return resolve();
        if (limit && limit < file.size) return reject(`文件大小不能超过${~~(limit / 1000)}KB`);
        const extension = file.name.split('.').pop()!.toLowerCase();
        if (accept && !accept.toLowerCase().includes(extension)) return reject(`仅支持${accept}文件`);
        resolve(file);
      };
      element.oncancel = () => resolve();
      element.click();
    });
  } finally {
    element.onchange = null;
    element.oncancel = null;
    element.remove();
  }
}

/**
 * Base64图片转二进制
 * @param base64:Base64 图片数据
 * @returns 二进制数据
 */
export function base64ToBlob(base64: string): Blob | undefined {
  const [prefix, data] = base64?.split('base64,', 2) ?? [];
  const type = prefix?.match(/:(.*?);/)?.[1];
  const str = atob(data ?? '');
  if (!type || !str?.length) return;
  let n = str.length;
  const buffer = new Uint8Array(n);
  while (n--) {
    buffer[n] = str.charCodeAt(n);
  }
  return new Blob([buffer], { type });
}

/**
 * 文本转二进制
 * @param text 文本字符
 * @returns 二进制数据
 */
export function textToBlob(text: string): Blob | undefined {
  if (!text.length) return;
  return new Blob([text], { type: 'text/plain' });
}

/**
 * 文本文件解码
 * @param file 文件域
 * @returns 文本字符串
 */
export async function decodeTextFile(file: File): Promise<string | undefined> {
  if (!file.size) return;
  const decoder = new TextDecoder();
  const buffer = await file.arrayBuffer();
  return decoder.decode(buffer);
}
