/**
 * 文件管理页 — 组合各域 composable，供 FilesPage.vue 使用
 */
import { computed, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useFilesClipboard } from '@/composables/useFilesClipboard'
import { useFilesHotkeys } from '@/composables/useFilesHotkeys'
import { useFilesStore } from '@/stores/files'
import type { FileEntry } from '@/types/api'
import {
  FILE_EXT_FILTERS,
  isArchiveFile,
  matchesExtensionFilter,
  sortFileEntries,
  type FileSortKey,
} from '@/utils/fileSort'
import {
  formatOwnerChip,
  isEntryLikelyUnreadable,
  ownerChipColor,
  permissionTooltip,
} from '@/utils/fileMode'
import { isPreloadEligible } from '@/utils/filePreload'
import { validatePathSegment } from '@/utils/remotePath'
import { required } from '@/utils/validation'
import { useFilesActions } from './useFilesActions'
import { useFilesBrowse } from './useFilesBrowse'
import { useFilesEditor } from './useFilesEditor'
import { useFilesNavigation } from './useFilesNavigation'
import { useFilesPermissions } from './useFilesPermissions'
import { useFilesSelection } from './useFilesSelection'

export function useFilesPage() {
  const fileFilter = ref('')
  const extFilter = ref('')
  const sortBy = ref<FileSortKey>('name')
  const sortOptions = [
    { title: '名称', value: 'name' as const },
    { title: '大小', value: 'size' as const },
    { title: '修改时间', value: 'modified' as const },
  ]

  const store = useFilesStore()
  const {
    selectedServer,
    currentPath,
    files,
    loading,
    browseError,
    pageReady,
    setupSudoLoading,
    setupSudoDone,
  } = storeToRefs(store)

  const selection = useFilesSelection()
  const { selectedFiles, selectedFileCount, clearSelection } = selection

  const { emptyHint, browse, browseCurrent, invalidateAfterMutation, loadingVisible } =
    useFilesBrowse(fileFilter)

  const permissions = useFilesPermissions({ browse })
  const {
    sshUserForFiles,
    filesAccessHint,
    dismissFilesAccessHint,
    setupFilesSudo,
  } = permissions

  const nav = useFilesNavigation({
    browse,
    refreshFilesCapability: permissions.refreshFilesCapability,
    clearSelection,
  })

  const actionLoading = ref(false)

  const editor = useFilesEditor({
    browse,
    invalidateAfterMutation,
    actionLoading,
  })

  const actions = useFilesActions({
    browse,
    invalidateAfterMutation,
    selection,
    openEntry: nav.openEntry,
    editFile: editor.editFile,
    previewFile: editor.previewFile,
    openInTerminal: nav.openInTerminal,
    editorWorkbench: editor.editorWorkbench,
    waitForEditorWorkbench: editor.waitForEditorWorkbench,
    actionLoading,
  })

  const { hasClipboard, clipboardSummary, canPasteOnServer } = useFilesClipboard()
  const canPasteHere = computed(() => canPasteOnServer(selectedServer.value))

  const displayedFiles = computed(() => {
    let list = sortFileEntries(files.value, sortBy.value, 'asc')
    const ext = extFilter.value
    if (ext) list = list.filter((f) => matchesExtensionFilter(f.name, ext))
    const q = fileFilter.value.trim().toLowerCase()
    if (q) list = list.filter((f) => f.name.toLowerCase().includes(q))
    return list
  })

  const statusSummary = computed(() => {
    const dirs = files.value.filter((f) => f.type === 'directory').length
    const regular = files.value.filter((f) => f.type === 'file').length
    const links = files.value.filter((f) => f.type === 'symlink').length
    const preloadable = files.value.filter(isPreloadEligible).length
    const parts = [`${dirs} 个目录`, `${regular} 个文件`]
    if (links) parts.push(`${links} 个链接`)
    if (preloadable) parts.push(`${preloadable} 个 ≤300KB 可预加载`)
    return `${parts.join('，')} · ${currentPath.value}`
  })

  function isArchiveName(name: string): boolean {
    return isArchiveFile(name)
  }

  function entryIcon(item: FileEntry): string {
    if (item.type === 'directory') return 'mdi-folder'
    if (item.type === 'symlink') return 'mdi-link-variant'
    return 'mdi-file-outline'
  }

  function entryIconColor(item: FileEntry): string {
    if (item.type === 'directory') return 'amber'
    if (item.type === 'symlink') return 'teal'
    return 'blue'
  }

  function isRegularFile(item: FileEntry): boolean {
    return item.type === 'file'
  }

  const fileHeaders = [
    { title: '名称', key: 'name' },
    { title: '归属', key: 'owner', width: 110, sortable: false },
    { title: '大小', key: 'size', width: 120 },
    { title: '修改时间', key: 'modified', width: 180 },
    { title: '操作', key: 'actions', width: 160, sortable: false, align: 'end' as const },
  ]

  useFilesHotkeys(
    {
      refresh: browseCurrent,
      goUp: nav.goUp,
      renameSelection: () => {
        if (selectedFiles.value.length === 1) {
          actions.startRename(selectedFiles.value[0])
        }
      },
      deleteSelection: () => {
        if (selectedFiles.value.length > 0) void actions.batchDelete()
      },
      selectAll: () => {
        selectedFiles.value = [...displayedFiles.value]
      },
      copySelection: () => actions.copyToClipboard(),
      cutSelection: () => actions.cutToClipboard(),
      pasteClipboard: () => {
        void actions.pasteClipboard()
      },
    },
    selectedFiles,
    canPasteHere,
  )

  return {
    FILE_EXT_FILTERS,
    validatePathSegment,
    required,
    fileFilter,
    extFilter,
    sortBy,
    sortOptions,
    selectedServer,
    currentPath,
    files,
    loading,
    loadingVisible,
    browseError,
    pageReady,
    setupSudoLoading,
    setupSudoDone,
    serverList: nav.serverList,
    filteredServerList: nav.filteredServerList,
    serverSearchQuery: nav.serverSearchQuery,
    serversLoading: nav.serversLoading,
    onServerChange: nav.onServerChange,
    browseCurrent,
    filesAccessHint,
    dismissFilesAccessHint,
    setupFilesSudo,
    sshUserForFiles,
    statusSummary,
    hasClipboard,
    clipboardSummary,
    pasteDestLabel: actions.pasteDestLabel,
    canPasteHere,
    breadcrumbs: nav.breadcrumbs,
    onBreadcrumbClick: nav.onBreadcrumbClick,
    canGoUp: nav.canGoUp,
    goUp: nav.goUp,
    selectedFiles,
    selectedFileCount,
    displayedFiles,
    fileHeaders,
    fileRowProps: actions.fileRowProps,
    dropActive: actions.dropActive,
    onDropFiles: actions.onDropFiles,
    emptyHint,
    entryIcon,
    entryIconColor,
    isEntryLikelyUnreadable,
    formatOwnerChip,
    ownerChipColor,
    permissionTooltip,
    formatSize: editor.formatSize,
    isRegularFile,
    isArchiveName,
    showUpload: actions.showUpload,
    uploadFiles: actions.uploadFiles,
    uploading: actions.uploading,
    doUpload: actions.doUpload,
    showNewFile: actions.showNewFile,
    newFileName: actions.newFileName,
    doNewFile: actions.doNewFile,
    openNewFileDialog: actions.openNewFileDialog,
    showMkdir: actions.showMkdir,
    mkdirName: actions.mkdirName,
    doMkdir: actions.doMkdir,
    showFileDelete: actions.showFileDelete,
    deletingFile: actions.deletingFile,
    doDeleteFile: actions.doDeleteFile,
    showRename: actions.showRename,
    newName: actions.newName,
    doRename: actions.doRename,
    showChmod: actions.showChmod,
    chmodFile: actions.chmodFile,
    chmodLoading: actions.chmodLoading,
    doChmod: actions.doChmod,
    showCompress: actions.showCompress,
    compressDest: actions.compressDest,
    compressFormat: actions.compressFormat,
    compressPaths: actions.compressPaths,
    doCompress: actions.doCompress,
    showDecompress: actions.showDecompress,
    decompressSource: actions.decompressSource,
    decompressDest: actions.decompressDest,
    doDecompress: actions.doDecompress,
    showContextMenu: actions.showContextMenu,
    contextX: actions.contextX,
    contextY: actions.contextY,
    contextFile: actions.contextFile,
    contextAction: actions.contextAction,
    actionLoading,
    batchDelete: actions.batchDelete,
    openCompressDialog: actions.openCompressDialog,
    showPreview: editor.showPreview,
    previewTitle: editor.previewTitle,
    previewContent: editor.previewContent,
    previewLoading: editor.previewLoading,
    editorWorkbench: editor.editorWorkbench,
    onEditorSaved: editor.onEditorSaved,
    navigateToPath: nav.navigateToPath,
    pasteClipboard: actions.pasteClipboard,
    editFile: editor.editFile,
    previewFile: editor.previewFile,
    confirmDeleteFile: actions.confirmDeleteFile,
    openInTerminal: nav.openInTerminal,
  }
}
