/**
 * 文件编辑 Composable
 * 提供文件编辑相关的逻辑，包括草稿管理、保存、撤销等
 */

import { ref, computed, watch } from 'vue'
import { Message } from '@arco-design/web-vue'
import { STORAGE_KEYS, FILE_EXTENSIONS, FILE_SIZE_THRESHOLDS } from '@/utils/constants'
import { getExt } from '@/utils/fileUtils'
import {
  isImageFile, isVideoFile, isAudioFile, isPdfFile,
  isExcelFile, isWordFile, isCsvFile,
  isTextEditable, isConfigFile
} from '@/utils/fileTypeHelpers'
import { useFileOperations } from './useFileOperations'
import type { FileItem } from '@/types/file-system'

export interface UseFileEditOptions {
  currentFilePath?: import('vue').Ref<FileItem | null>
  currentDirectory?: import('vue').Ref<string>
}

// 文件大小限制（5MB）
const MAX_TEXT_FILE_SIZE = 5 * 1024 * 1024 // 5MB

export function useFileEdit(options: UseFileEditOptions = {}) {
  const { currentFilePath = ref(''), currentDirectory = ref('') } = options

  // 文件内容
  const fileContent = ref('')
  const originalContent = ref('')

  // 当前文件路径（用于验证更新是否来自当前文件）
  const currentFilePathRef = ref('')

  // 编辑状态
  const isEditMode = ref(false)
  const fileContentHeight = ref(400)
  const isBinaryFile = ref(false)

  // 草稿管理
  const draftKey = ref('')

  // 保存状态
  const isSaving = ref(false)

  // 文件版本跟踪（用于防止切换文件后的过期更新）
  const fileVersion = ref(0)

  // 使用文件操作 composable
  const { readFile, writeFile } = useFileOperations({
    onSuccess: (operation, data) => {
      // 可以在这里添加成功处理逻辑
    },
    onError: (operation, error) => {
      Message.error(`${operation} 失败: ${error.message}`)
    }
  })

  /**
   * 获取文件路径（从 FileItem 对象或字符串中提取）
   */
  const getFilePath = (input: any): string => {
    if (!input) return ''
    if (typeof input === 'string') return input
    if (input.path) return input.path
    return ''
  }

  // 已知二进制扩展名（无需读取内容即可判定）
  const KNOWN_BINARY_EXTS = new Set([
    'exe', 'dll', 'so', 'bin', 'dat', 'db', 'sqlite', 'pdb', 'idb',
    'lib', 'obj', 'o', 'a', 'class', 'pyc', 'pyo', 'wasm',
    'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'iso', 'img', 'dmg',
    'msi', 'jar', 'war', 'ear', 'apk'
  ])

  /**
   * 判断是否为二进制文件（基于扩展名）
   * 返回值: true=已知二进制, false=已知非二进制(文本/媒体/Office), null=未知需检测
   */
  const isBinaryFileByExt = (filepath: string | FileItem): boolean | null => {
    const path = getFilePath(filepath)
    const ext = getExt(path)
    if (!ext) return null // 无扩展名返回 null，表示需要进一步检测

    // 已知二进制扩展名 → 直接判定
    if (KNOWN_BINARY_EXTS.has(ext)) return true

    // 媒体文件（可预览，不算二进制）
    const isMediaFile = isImageFile(path) ||
                       isVideoFile(path) ||
                       isAudioFile(path) ||
                       isPdfFile(path) ||
                       ['html', 'htm', 'md', 'markdown'].includes(ext)

    // Office 文件和 CSV（可预览）
    const isOfficeFile = isExcelFile(path) || isWordFile(path) || isCsvFile(path)

    // 文本或代码文件（可编辑）
    const isTextFile = isTextEditable(path) || isConfigFile(path) ||
                      FILE_EXTENSIONS.CODE.includes(ext)

    // 如果是媒体文件、Office 文件或文本文件，就不是二进制
    if (isMediaFile || isOfficeFile || isTextFile) return false

    // 其他扩展名未知，需要内容检测
    return null
  }

  /**
   * 计算属性：当前视图是否可编辑
   * 图片、视频、音频、PDF、二进制文件不可编辑
   */
  const isEditableView = computed(() => {
    const path = getFilePath(currentFilePath.value)
    if (!path) return false
    const binaryCheck = isBinaryFileByExt(path)
    return !isImageFile(path) &&
           !isVideoFile(path) &&
           !isAudioFile(path) &&
           !isPdfFile(path) &&
           binaryCheck !== true  // true 表示是二进制，不可编辑；false 或 null 表示可尝试编辑
  })

  /**
   * 计算属性：文件内容是否改变
   */
  const contentChanged = computed(() => {
    return fileContent.value !== '' &&
           originalContent.value !== undefined &&
           originalContent.value !== fileContent.value
  })

  /**
   * 计算属性：是否可以保存
   */
  const canSaveFile = computed(() => {
    return isEditableView.value && contentChanged.value
  })

  /**
   * 计算属性：是否可以重置
   */
  const canResetContent = computed(() => {
    return contentChanged.value && originalContent.value !== undefined
  })

  /**
   * 检测文件内容是否为二进制
   */
  const detectBinaryContent = (content: string): boolean => {
    if (!content || content.length === 0) return false

    // 检查前 1000 个字符中二进制字符的比例
    const checkLength = Math.min(content.length, 1000)
    let binaryCharCount = 0

    for (let i = 0; i < checkLength; i++) {
      const charCode = content.charCodeAt(i)
      // 空字节肯定是二进制
      // 控制字符（charCode < 32）除了 Tab(9)、LF(10)、CR(13) 外都是二进制
      if (charCode === 0 || (charCode < 32 && charCode !== 9 && charCode !== 10 && charCode !== 13)) {
        binaryCharCount++
      }
    }

    // 如果二进制字符超过 5%，认为是二进制文件
    const binaryRatio = binaryCharCount / checkLength
    return binaryRatio > 0.05
  }

  /**
   * 读取文件内容
   */
  const loadFile = async (path: string) => {
    try {
      isBinaryFile.value = false

      // 记录当前加载的文件路径，用于后续验证更新
      currentFilePathRef.value = path

      // 增加文件版本号，使之前的过期更新失效
      fileVersion.value++

      // 注意：不再清空内容，避免 HTML 预览切换时闪烁
      // 新内容加载完成后会直接替换旧内容

      const filename = getFilePath(path)
      const ext = getExt(filename)

      // Office 文件直接读取内容进行预览，跳过二进制检测
      if (isExcelFile(filename) || isWordFile(filename)) {
        const content = await readFile(path)
        fileContent.value = content
        originalContent.value = content
        isEditMode.value = false
        return
      }

      // 先检查扩展名，如果是已知的二进制文件，直接生成提示信息
      const binaryCheck = isBinaryFileByExt(filename)
      if (binaryCheck === true) {
        isBinaryFile.value = true

        const fileTypeDescriptions: Record<string, string> = {
          'exe': '可执行文件',
          'dll': '动态链接库',
          'so': '共享库',
          'bin': '二进制文件',
          'dat': '数据文件',
          'db': '数据库文件',
          'sqlite': 'SQLite 数据库',
          'zip': 'ZIP 压缩文件',
          'rar': 'RAR 压缩文件',
          '7z': '7Z 压缩文件',
          'tar': 'TAR 归档文件',
          'gz': 'GZ 压缩文件',
          'bz2': 'BZ2 压缩文件',
          'xz': 'XZ 压缩文件',
          'iso': '光盘镜像',
          'img': '磁盘镜像',
          'dmg': 'DMG 镜像',
          'pdb': '程序数据库',
          'idb': 'IDA 数据库',
          'lib': '库文件',
          'obj': '目标文件',
          'o': '目标文件',
          'a': '静态库'
        }

        const fileTypeDesc = fileTypeDescriptions[ext] || `${ext.toUpperCase()} 文件`
        const fileName = filename.split('\\').pop() || filename.split('/').pop() || filename

        fileContent.value = `================================================================
文件信息：${fileTypeDesc}
================================================================

文件名:    ${fileName}
完整路径:  ${filename}
文件类型:  ${fileTypeDesc}

================================================================
ℹ️  这是已知的二进制文件类型，不支持文本预览

💡 提示:
   • 右键菜单 → "使用系统程序打开" 在默认应用中打开
   • 右键菜单 → "在资源管理器中显示" 查看文件位置
================================================================`
        originalContent.value = fileContent.value
        isEditMode.value = false
        return
      }

      // 对于无扩展名或未知类型文件，先尝试读取
      const content = await readFile(path)

      // 检查文件大小
      const fileSize = content.length // UTF-16 字符数
      if (fileSize > MAX_TEXT_FILE_SIZE) {
        const sizeMB = (fileSize / 1024 / 1024).toFixed(2)
        const fileName = filename.split('\\').pop() || filename.split('/').pop() || filename

        fileContent.value = `================================================================
⚠️  文件过大 (${sizeMB} MB)
================================================================

文件名:    ${fileName}
完整路径:  ${filename}
文件大小:  ${sizeMB} MB

================================================================
当前文件大小超过 5MB，不适合在编辑器中打开。

💡 建议：
   • 使用命令行工具查看部分内容
   • 将文件拆分成多个小文件
   • 使用专门的工具处理大文件
================================================================`
        originalContent.value = fileContent.value
        isEditMode.value = false
        return
      }

      // 检测是否为二进制内容
      if (detectBinaryContent(content)) {
        isBinaryFile.value = true
        const fileTypeDesc = ext ? `${ext.toUpperCase()} 文件` : '未知类型文件'
        const fileName = filename.split('\\').pop() || filename.split('/').pop() || filename

        // 根据是否有扩展名，显示不同提示
        const isUnknownType = !ext
        const messageTitle = isUnknownType ? '文件信息（未知类型）' : `文件信息：${fileTypeDesc}`
        const messageDesc = isUnknownType
          ? '此文件没有扩展名，且内容检测显示为二进制格式'
          : `此文件扩展名为 .${ext}，但内容检测显示为二进制格式`

        fileContent.value = `================================================================
${messageTitle}
================================================================

文件名:    ${fileName}
完整路径:  ${filename}
${ext ? `文件类型:  ${fileTypeDesc}\n` : ''}

================================================================
ℹ️  ${messageDesc}，不支持文本预览

💡 提示:
   • 右键菜单 → "使用系统程序打开" 在默认应用中打开
   • 右键菜单 → "在资源管理器中显示" 查看文件位置
================================================================`
        originalContent.value = fileContent.value
        isEditMode.value = false
        return
      }

      // 正常文本文件
      fileContent.value = content
      originalContent.value = content

      // 加载草稿（如果存在）
      loadDraft(path)
    } catch (error) {
      Message.error(`读取文件失败: ${error}`)
    }
  }

  /**
   * 保存文件内容
   */
  const saveFile = async (path?: string, isShortcut: boolean = false) => {
    // 获取目标路径（优先使用传入的 path，否则从 currentFilePath 中提取）
    let targetPath = path
    if (!targetPath && currentFilePath.value) {
      targetPath = getFilePath(currentFilePath.value)
    }

    if (!targetPath) {
      Message.error('没有选中的文件')
      return
    }

    // 检查内容是否真的改变了
    if (fileContent.value === originalContent.value) {
      if (!isShortcut) {
        Message.info('文件内容未变更')
      }
      return
    }

    isSaving.value = true

    try {
      await writeFile(targetPath, fileContent.value)
      originalContent.value = fileContent.value

      // 清除草稿
      clearDraft()

      if (!isShortcut) {
        Message.success('保存成功')
      }
    } catch (error) {
      Message.error(`保存失败: ${error}`)
    } finally {
      // 延迟清除保存状态
      setTimeout(() => {
        isSaving.value = false
      }, isShortcut ? 300 : 500)
    }
  }

  /**
   * 保存草稿
   */
  const saveDraft = () => {
    if (!currentFilePath.value) return

    // Office 文件不支持草稿功能
    const path = getFilePath(currentFilePath.value)
    if (isExcelFile(path) || isWordFile(path)) {
      return
    }

    const key = `${STORAGE_KEYS.FILESYSTEM.FILE_DRAFT}-${currentFilePath.value}`
    const draft = {
      content: fileContent.value,
      savedAt: Date.now()
    }

    try {
      localStorage.setItem(key, JSON.stringify(draft))
      draftKey.value = key
    } catch (error) {
      console.error('保存草稿失败:', error)
    }
  }

  /**
   * 加载草稿
   */
  const loadDraft = (path: string) => {
    // Office 文件不支持草稿功能，并清除已有的草稿
    if (isExcelFile(path) || isWordFile(path)) {
      const key = `${STORAGE_KEYS.FILESYSTEM.FILE_DRAFT}-${path}`
      try {
        localStorage.removeItem(key)
        console.debug('[useFileEdit] 已清除 Office 文件草稿:', path)
      } catch (error) {
        console.error('清除草稿失败:', error)
      }
      return
    }

    const key = `${STORAGE_KEYS.FILESYSTEM.FILE_DRAFT}-${path}`
    draftKey.value = key

    try {
      const stored = localStorage.getItem(key)
      if (stored) {
        const draft = JSON.parse(stored)
        const ageInHours = (Date.now() - draft.savedAt) / (1000 * 60 * 60)

        // 如果草稿超过 24 小时，自动清除
        if (ageInHours > 24) {
          clearDraft()
          return
        }

        // 恢复草稿内容
        fileContent.value = draft.content
        Message.info('已恢复未保存的草稿')
      }
    } catch (error) {
      console.error('加载草稿失败:', error)
    }
  }

  /**
   * 清除草稿
   */
  const clearDraft = () => {
    if (!draftKey.value) return

    try {
      localStorage.removeItem(draftKey.value)
      draftKey.value = ''
    } catch (error) {
      console.error('清除草稿失败:', error)
    }
  }

  /**
   * 仅更新文件路径（重命名场景：内容不变，只切换路径关联）
   * 迁移草稿 key，更新 currentFilePathRef
   */
  const updateFilePath = (newPath: string) => {
    const oldPath = currentFilePathRef.value

    // 迁移草稿（旧 key → 新 key）
    if (draftKey.value && oldPath !== newPath) {
      try {
        const draft = localStorage.getItem(draftKey.value)
        if (draft) {
          const newKey = `${STORAGE_KEYS.FILESYSTEM.FILE_DRAFT}-${newPath}`
          localStorage.setItem(newKey, draft)
          localStorage.removeItem(draftKey.value)
          draftKey.value = newKey
        }
      } catch (error) {
        console.warn('[useFileEdit] 草稿迁移失败:', error)
      }
    }

    // 只更新内部路径字符串引用，不触碰 currentFilePath（它是 FileItem 对象，由父组件管理）
    // 这样不会触发 watch → clearDraft
    currentFilePathRef.value = newPath
  }

  /**
   * 重置文件内容
   */
  const resetContent = () => {
    if (originalContent.value !== undefined) {
      fileContent.value = originalContent.value
      Message.info('已恢复原始内容')
    }
  }

  /**
   * 清空文件内容
   */
  const clearContent = () => {
    fileContent.value = ''
    originalContent.value = ''
  }

  /**
   * 切换编辑模式
   */
  const toggleEditMode = () => {
    isEditMode.value = !isEditMode.value
  }

  /**
   * 进入编辑模式
   */
  const enterEditMode = () => {
    isEditMode.value = true
  }

  /**
   * 退出编辑模式
   */
  const exitEditMode = () => {
    // 如果有未保存的更改，提示用户
    if (contentChanged.value) {
      // 这里可以添加确认对话框
      // 暂时直接退出
    }
    isEditMode.value = false
  }

  /**
   * 更新文件内容（仅版本号匹配时接受，防止快速切换文件时旧更新覆盖新内容）
   */
  const updateContent = (content: string, expectedVersion?: number) => {
    if (expectedVersion !== undefined && expectedVersion !== fileVersion.value) {
      console.debug('[useFileEdit] 忽略过期更新（版本不匹配）:', {
        expected: expectedVersion,
        current: fileVersion.value,
        content: content.substring(0, 50)
      })
      return
    }

    if (fileContent.value !== content) {
      fileContent.value = content
    }
  }

  /**
   * 设置编辑器高度
   */
  const setEditorHeight = (height: number) => {
    fileContentHeight.value = Math.max(200, height)
  }

  /**
   * 判断文件是否在当前目录
   */
  const isFileInCurrentDirectory = (filePathInput: any): boolean => {
    const filePath = getFilePath(filePathInput)
    if (!filePath || !currentDirectory.value) {
      return true
    }
    return filePath.startsWith(currentDirectory.value)
  }

  // 监听文件路径变化，清除草稿
  watch(currentFilePath, (newPath, oldPath) => {
    if (newPath !== oldPath) {
      clearDraft()
    }
  })

  return {
    // 状态
    fileContent,
    originalContent,
    isEditMode,
    fileContentHeight,
    isSaving,
    isBinaryFile,
    draftKey,
    fileVersion,

    // 计算属性
    contentChanged,
    canSaveFile,
    canResetContent,
    isEditableView,

    // 文件操作
    loadFile,
    saveFile,
    updateContent,

    // 草稿管理
    saveDraft,
    loadDraft,
    clearDraft,

    // 编辑模式
    toggleEditMode,
    enterEditMode,
    exitEditMode,

    // 其他
    resetContent,
    clearContent,
    updateFilePath,
    setEditorHeight,

    // 文件类型检查
    isBinaryFileByExt,
    isFileInCurrentDirectory
  }
}
