/**
 * 文件工具函数集合
 *
 * @module utils/fileUtils
 * @description 提供文件相关的通用工具函数，避免代码重复
 */

import { FILE_ICON_MAP, FILE_ICONS, BYTE_UNITS, FILE_SIZE_FORMAT } from './constants'

/**
 * 路径分隔符正则（匹配 Windows 和 Unix 风格）
 * @type {RegExp}
 */
const PATH_SEPARATOR_REGEX = /[/\\]/

/**
 * 规范化路径分隔符（统一为正斜杠）
 * @param {string} path - 文件路径
 * @returns {string} 规范化后的路径
 */
export const normalizePathSeparators = (path) => {
  if (!path) return ''
  return path.replace(/\\/g, '/')
}

/**
 * HTML 转义，防止 XSS
 * @param {string} str - 原始字符串
 * @returns {string} 转义后的字符串
 */
export const escapeHtml = (str) => {
  if (str == null) return ''
  return String(str)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;')
}

/**
 * 轻量 HTML 消毒（用于渲染远程 Markdown 等不可信 HTML 片段）
 * 移除 script/iframe/object/embed 标签和 on* 事件属性
 */
export const sanitizeHtml = (html) => {
  if (!html) return ''
  return String(html)
    .replace(/<script\b[^<]*(?:<\/script>|$)/gi, '')
    .replace(/<iframe\b[^<]*(?:<\/iframe>|$)/gi, '')
    .replace(/<object\b[^<]*(?:<\/object>|$)/gi, '')
    .replace(/<embed\b[^>]*\/?>/gi, '')
    .replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, '')
    .replace(/\s+on\w+\s*=\s*[^\s>]*/gi, '')
}

/**
 * 获取文件扩展名（路径安全）
 * @param {string} path - 文件路径
 * @returns {string} 扩展名（小写，不含点号）
 */
export const getExt = (path) => {
  if (!path) return ''
  const dot = path.lastIndexOf('.')
  const slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'))
  if (dot === -1 || dot < slash) return ''
  return path.slice(dot + 1).toLowerCase()
}

/**
 * 格式化文件大小
 * @param {number} bytes - 文件大小（字节）
 * @returns {string} 格式化后的文件大小字符串
 *
 * @example
 * formatBytes(1024) // "1.00 KB"
 * formatBytes(1048576) // "1.00 MB"
 * formatBytes(0) // "0 B"
 */
export function formatBytes(bytes) {
  if (!bytes || bytes === 0) return '0 B'
  if (typeof bytes !== 'number' || isNaN(bytes)) return '0 B'

  const unit = FILE_SIZE_FORMAT.UNIT
  const decimals = FILE_SIZE_FORMAT.DECIMAL_PLACES

  if (bytes < unit) return bytes + ' B'

  const exp = Math.min(Math.floor(Math.log(bytes) / Math.log(unit)), BYTE_UNITS.length - 1)
  const value = bytes / Math.pow(unit, exp)
  const unitSymbol = BYTE_UNITS[exp]

  return value.toFixed(decimals) + ' ' + unitSymbol
}

/**
 * 从文件路径中提取文件名
 * @param {string} path - 文件路径
 * @returns {string} 文件名
 *
 * @example
 * getFileName('/home/user/docs/file.txt') // "file.txt"
 * getFileName('C:\\Users\\user\\file.txt') // "file.txt"
 * getFileName('file.txt') // "file.txt"
 */
export function getFileName(path) {
  if (!path) return ''
  const parts = path.split(PATH_SEPARATOR_REGEX)
  return parts[parts.length - 1] || path
}


/**
 * 根据文件信息获取对应的图标
 * @param {Object} fileInfo - 文件信息对象
 * @param {boolean} fileInfo.is_dir - 是否为目录
 * @param {string} fileInfo.name - 文件名
 * @returns {string} 文件图标（emoji）
 *
 * @example
 * getFileIcon({ is_dir: true }) // "📁"
 * getFileIcon({ is_dir: false, name: 'image.png' }) // "🖼️"
 * getFileIcon({ is_dir: false, name: 'document.pdf' }) // "📕"
 */
export function getFileIcon(fileInfo) {
  if (!fileInfo) return FILE_ICONS.FILE

  // 如果是目录
  if (fileInfo.is_dir) {
    return FILE_ICONS.FOLDER
  }

  // 获取文件扩展名
  const ext = getExt(fileInfo.name)

  // 从映射表中查找图标
  return FILE_ICON_MAP.get(ext) || FILE_ICONS.FILE
}

/**
 * 规范化文件路径（将反斜杠转换为正斜杠，并进行URL编码）
 * @param {string} path - 原始路径
 * @param {boolean} encode - 是否进行URL编码（用于URL路径）
 * @returns {string} 规范化后的路径
 *
 * @example
 * normalizeFilePath('C:\\Users\\user\\file.txt') // "C:/Users/user/file.txt"
 * normalizeFilePath('/home/user/file.txt') // "/home/user/file.txt"
 * normalizeFilePath('E:/中文路径/file.pdf', true) // "E:/%E4%B8%AD%E6%96%87%E8%B7%AF%E5%BE%84/file.pdf"
 */
export function normalizeFilePath(path, encode = false) {
  if (!path) return ''
  const normalized = normalizePathSeparators(path)

  // 如果需要编码，则使用 encodeURIComponent
  if (encode) {
    const parts = normalized.split('/')
    // 只对包含需要编码字符的路径段进行编码
    // Windows 路径格式: E:/path/to/file，第一部分是盘符（如 E:），不应编码
    return parts.map((segment, index) => {
      // 盘符部分（如 "E:"）不编码
      if (index === 0 && /^[A-Za-z]:$/.test(segment)) {
        return segment
      }
      // 检查是否需要编码（包含非ASCII字符或特殊字符）
      if (/[^A-Za-z0-9\-_.~]/.test(segment)) {
        return encodeURIComponent(segment)
      }
      return segment
    }).join('/')
  }

  return normalized
}

/**
 * 获取路径使用的分隔符（Windows 反斜杠或 Unix 正斜杠）
 * @param {string} path - 文件路径
 * @returns {string} 分隔符 '\\' 或 '/'
 */
export function getPathSeparator(path) {
  return path.includes('\\') ? '\\' : '/'
}

/**
 * 获取父目录路径
 * @param {string} path - 文件路径
 * @returns {string} 父目录路径
 *
 * @example
 * getParentPath('/home/user/docs/file.txt') // "/home/user/docs"
 * getParentPath('/home/user/docs/') // "/home/user"
 */
export function getParentPath(path) {
  if (!path) return ''

  const normalizedPath = normalizePathSeparators(path)
  const lastSlashIndex = normalizedPath.lastIndexOf('/')

  if (lastSlashIndex <= 0) {
    if (/^[A-Za-z]:$/.test(normalizedPath)) {
      return normalizedPath + '/'
    }
    return normalizedPath || '/'
  }

  const parentPath = normalizedPath.substring(0, lastSlashIndex)

  // 盘符根目录下文件：E:/file.txt → E:/
  if (/^[A-Za-z]:$/.test(parentPath)) {
    return parentPath + '/'
  }

  return parentPath || '/'
}


/**
 * 文件列表排序：文件夹优先，支持多字段排序
 * @param {Array} fileList - 文件列表
 * @param {Object} options - 排序选项 { sortBy, sortOrder }
 * @returns {Array} 排序后的文件列表
 *
 * @example
 * sortFileList(fileList, { sortBy: 'name', sortOrder: 'asc' })
 */

/**
 * 格式化文件修改时间
 * @param {string} t - 时间字符串
 * @returns {string} 格式化后的时间，如 2026/04/11 14:30
 */
export function formatFileTime(t) {
  if (!t) return ''
  const d = new Date(t)
  if (isNaN(d.getTime())) return t
  const pad = n => String(n).padStart(2, '0')
  return `${d.getFullYear()}/${pad(d.getMonth()+1)}/${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}

export function sortFileList(fileList, options = {}) {
  if (!Array.isArray(fileList)) return fileList

  const { sortBy = 'name', sortOrder = 'asc' } = options
  const dir = sortOrder === 'desc' ? 1 : -1

  return fileList.sort((a, b) => {
    // 文件夹始终排在前面
    if (a.isDir !== b.isDir) {
      return a.isDir ? -1 : 1
    }

    let cmp = 0
    switch (sortBy) {
      case 'size':
        cmp = (a.size || 0) - (b.size || 0)
        break
      case 'type': {
        cmp = getExt(a.name).localeCompare(getExt(b.name))
        break
      }
      case 'modified_time': {
        const ta = a.modified_time ? new Date(a.modified_time).getTime() : 0
        const tb = b.modified_time ? new Date(b.modified_time).getTime() : 0
        cmp = ta - tb
        break
      }
      default: // name
        cmp = a.name.localeCompare(b.name)
    }
    return cmp * dir
  })
}
