/**
 * 文件工具函数
 */

/**
 * 格式化文件大小
 * @param bytes 文件大小（字节）
 * @returns 格式化后的文件大小字符串
 */
export function formatFileSize(bytes: number): string {
  if (bytes === 0) return '0 B'

  const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
  const k = 1024
  const i = Math.floor(Math.log(bytes) / Math.log(k))

  return `${(bytes / Math.pow(k, i)).toFixed(2)} ${units[i]}`
}

/**
 * 格式化日期时间
 * @param dateString 日期字符串
 * @param format 格式化模板，默认 'YYYY-MM-DD HH:mm:ss'
 * @returns 格式化后的日期时间字符串
 */
export function formatDateTime(dateString: string, format: string = 'YYYY-MM-DD HH:mm:ss'): string {
  if (!dateString) return ''

  const date = new Date(dateString)

  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const hours = String(date.getHours()).padStart(2, '0')
  const minutes = String(date.getMinutes()).padStart(2, '0')
  const seconds = String(date.getSeconds()).padStart(2, '0')

  return format
    .replace('YYYY', String(year))
    .replace('MM', month)
    .replace('DD', day)
    .replace('HH', hours)
    .replace('mm', minutes)
    .replace('ss', seconds)
}

/**
 * 获取文件扩展名
 * @param filename 文件名
 * @returns 文件扩展名（包含点号）
 */
export function getFileExtension(filename: string): string {
  const lastDotIndex = filename.lastIndexOf('.')
  return lastDotIndex > -1 ? filename.substring(lastDotIndex) : ''
}

/**
 * 获取文件名（不含扩展名）
 * @param filename 文件名
 * @returns 不含扩展名的文件名
 */
export function getFileNameWithoutExtension(filename: string): string {
  const lastDotIndex = filename.lastIndexOf('.')
  return lastDotIndex > -1 ? filename.substring(0, lastDotIndex) : filename
}

/**
 * 判断是否为图片文件
 * @param mimeType MIME类型
 * @returns 是否为图片
 */
export function isImage(mimeType: string): boolean {
  return mimeType?.startsWith('image/') || false
}

/**
 * 判断是否为PDF文件
 * @param mimeType MIME类型
 * @returns 是否为PDF
 */
export function isPDF(mimeType: string): boolean {
  return mimeType === 'application/pdf'
}

/**
 * 判断是否为文档文件
 * @param mimeType MIME类型
 * @returns 是否为文档
 */
export function isDocument(mimeType: string): boolean {
  const documentTypes = [
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-powerpoint',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    'text/plain',
    'text/csv'
  ]
  return documentTypes.includes(mimeType)
}

/**
 * 判断是否为压缩包文件
 * @param mimeType MIME类型
 * @returns 是否为压缩包
 */
export function isArchive(mimeType: string): boolean {
  const archiveTypes = [
    'application/zip',
    'application/x-rar-compressed',
    'application/x-7z-compressed'
  ]
  return archiveTypes.includes(mimeType)
}

/**
 * 获取文件类型图标
 * @param mimeType MIME类型
 * @returns 图标名称
 */
export function getFileTypeIcon(mimeType: string): string {
  if (isImage(mimeType)) return 'picture'
  if (isPDF(mimeType)) return 'document'
  if (isDocument(mimeType)) return 'document'
  if (isArchive(mimeType)) return 'folder'
  return 'files'
}

/**
 * 下载文件
 * @param url 文件URL
 * @param filename 文件名
 * @returns Promise<void>
 */
export async function downloadFile(url: string, filename?: string): Promise<void> {
  try {
    const response = await fetch(url)
    if (!response.ok) {
      throw new Error('下载失败')
    }

    const blob = await response.blob()
    const blobUrl = window.URL.createObjectURL(blob)

    const link = document.createElement('a')
    link.href = blobUrl
    link.download = filename || getFilenameFromUrl(url)

    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)

    window.URL.revokeObjectURL(blobUrl)
  } catch (error) {
    console.error('下载文件失败:', error)
    throw error
  }
}

/**
 * 从URL中提取文件名
 * @param url URL地址
 * @returns 文件名
 */
function getFilenameFromUrl(url: string): string {
  try {
    const urlObj = new URL(url)
    const pathname = urlObj.pathname
    const parts = pathname.split('/')
    return parts[parts.length - 1] || 'download'
  } catch {
    return 'download'
  }
}

/**
 * 预览文件（新窗口打开）
 * @param url 文件URL
 */
export function previewFile(url: string): void {
  window.open(url, '_blank')
}

/**
 * 复制文件到剪贴板
 * @param file File对象
 * @returns Promise<boolean>
 */
export async function copyFileToClipboard(file: File): Promise<boolean> {
  try {
    await navigator.clipboard.write([
      new ClipboardItem({
        [file.type]: file
      })
    ])
    return true
  } catch (error) {
    console.error('复制文件失败:', error)
    return false
  }
}

/**
 * 读取文件为DataURL
 * @param file File对象
 * @returns Promise<string>
 */
export function readFileAsDataURL(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(reader.result as string)
    reader.onerror = reject
    reader.readAsDataURL(file)
  })
}

/**
 * 读取文件为文本
 * @param file File对象
 * @returns Promise<string>
 */
export function readFileAsText(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(reader.result as string)
    reader.onerror = reject
    reader.readAsText(file)
  })
}

/**
 * 计算文件哈希值（简单实现）
 * @param file File对象
 * @returns Promise<string>
 */
export async function calculateFileHash(file: File): Promise<string> {
  const buffer = await file.arrayBuffer()
  const hashBuffer = await crypto.subtle.digest('SHA-256', buffer)
  const hashArray = Array.from(new Uint8Array(hashBuffer))
  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
  return hashHex
}

/**
 * 压缩图片
 * @param file 图片文件
 * @param quality 压缩质量（0-1）
 * @param maxWidth 最大宽度
 * @param maxHeight 最大高度
 * @returns Promise<Blob>
 */
export async function compressImage(
  file: File,
  quality: number = 0.8,
  maxWidth: number = 1920,
  maxHeight: number = 1080
): Promise<Blob> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = (e) => {
      const img = new Image()
      img.onload = () => {
        const canvas = document.createElement('canvas')
        let width = img.width
        let height = img.height

        // 计算缩放比例
        if (width > maxWidth || height > maxHeight) {
          const ratio = Math.min(maxWidth / width, maxHeight / height)
          width = width * ratio
          height = height * ratio
        }

        canvas.width = width
        canvas.height = height

        const ctx = canvas.getContext('2d')
        if (ctx) {
          ctx.drawImage(img, 0, 0, width, height)
          canvas.toBlob(
            (blob) => {
              if (blob) {
                resolve(blob)
              } else {
                reject(new Error('压缩失败'))
              }
            },
            file.type,
            quality
          )
        } else {
          reject(new Error('无法创建canvas上下文'))
        }
      }
      img.onerror = reject
      img.src = e.target?.result as string
    }
    reader.onerror = reject
    reader.readAsDataURL(file)
  })
}

/**
 * 验证文件类型
 * @param file File对象
 * @param allowedTypes 允许的类型列表
 * @returns 是否通过验证
 */
export function validateFileType(file: File, allowedTypes: string[]): boolean {
  return allowedTypes.some(type => {
    if (type.startsWith('.')) {
      return file.name.toLowerCase().endsWith(type.toLowerCase())
    }
    return file.type.includes(type)
  })
}

/**
 * 验证文件大小
 * @param file File对象
 * @param maxSize 最大大小（字节）
 * @returns 是否通过验证
 */
export function validateFileSize(file: File, maxSize: number): boolean {
  return file.size <= maxSize
}

/**
 * 批量验证文件
 * @param files 文件列表
 * @param options 验证选项
 * @returns 验证结果
 */
export function validateFiles(
  files: File[],
  options: {
    allowedTypes?: string[]
    maxSize?: number
    maxCount?: number
  }
): { valid: boolean; errors: string[] } {
  const errors: string[] = []

  // 检查文件数量
  if (options.maxCount && files.length > options.maxCount) {
    errors.push(`最多只能上传 ${options.maxCount} 个文件`)
    return { valid: false, errors }
  }

  // 检查每个文件
  files.forEach((file, index) => {
    // 检查类型
    if (options.allowedTypes && !validateFileType(file, options.allowedTypes)) {
      errors.push(`文件 "${file.name}" 的类型不支持`)
    }

    // 检查大小
    if (options.maxSize && !validateFileSize(file, options.maxSize)) {
      const maxSizeMB = (options.maxSize / 1024 / 1024).toFixed(0)
      errors.push(`文件 "${file.name}" 大小超过 ${maxSizeMB}MB`)
    }
  })

  return {
    valid: errors.length === 0,
    errors
  }
}

/**
 * 生成唯一文件名
 * @param originalFilename 原始文件名
 * @returns 唯一文件名
 */
export function generateUniqueFilename(originalFilename: string): string {
  const ext = getFileExtension(originalFilename)
  const name = getFileNameWithoutExtension(originalFilename)
  const timestamp = Date.now()
  const random = Math.random().toString(36).substring(2, 8)
  return `${name}_${timestamp}_${random}${ext}`
}

/**
 * 创建缩略图
 * @param file 图片文件
 * @param width 缩略图宽度
 * @param height 缩略图高度
 * @returns Promise<string> DataURL
 */
export async function createThumbnail(
  file: File,
  width: number = 200,
  height: number = 200
): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = (e) => {
      const img = new Image()
      img.onload = () => {
        const canvas = document.createElement('canvas')
        canvas.width = width
        canvas.height = height

        const ctx = canvas.getContext('2d')
        if (ctx) {
          // 计算缩放比例，保持宽高比
          const scale = Math.min(width / img.width, height / img.height)
          const x = (width - img.width * scale) / 2
          const y = (height - img.height * scale) / 2

          ctx.drawImage(img, 0, 0, img.width, img.height, x, y, img.width * scale, img.height * scale)
          resolve(canvas.toDataURL(file.type, 0.8))
        } else {
          reject(new Error('无法创建canvas上下文'))
        }
      }
      img.onerror = reject
      img.src = e.target?.result as string
    }
    reader.onerror = reject
    reader.readAsDataURL(file)
  })
}
