import { ref, watch, computed, type Ref } from 'vue'
import { http } from '@/api'
import { useSnackbar } from '@/composables/useSnackbar'
import type { StagingEntry, StagingPreviewResult, UploadedSource } from './types'

type BrowseLocalResponse = {
  path: string
  entries: StagingEntry[]
}

type ValidateSourcePathResponse = {
  file_count: number
  size_bytes: number
}

function joinHostPath(dir: string, name: string): string {
  const base = dir.replace(/\/+$/, '')
  return `${base}/${name}`
}

export function usePushStaging(uploadedSource: Ref<UploadedSource | null>) {
  const snackbar = useSnackbar()

  const loading = ref(false)
  const currentPath = ref('')
  const entries = ref<StagingEntry[]>([])
  const previewOpen = ref(false)
  const previewLoading = ref(false)
  const previewResult = ref<StagingPreviewResult | null>(null)
  const renameOpen = ref(false)
  const renameTarget = ref<StagingEntry | null>(null)
  const renameValue = ref('')
  const renameLoading = ref(false)
  const deleteOpen = ref(false)
  const deleteTargets = ref<StagingEntry[]>([])
  const deleteLoading = ref(false)
  const selectedNames = ref<Set<string>>(new Set())

  const stagingRoot = () => uploadedSource.value?.sourcePath ?? ''

  const selectedCount = computed(() => selectedNames.value.size)

  const allSelected = computed(() => {
    const list = entries.value
    return list.length > 0 && list.every(e => selectedNames.value.has(e.name))
  })

  const someSelected = computed(() => selectedNames.value.size > 0 && !allSelected.value)

  function clearSelection() {
    selectedNames.value = new Set()
  }

  function isSelected(name: string): boolean {
    return selectedNames.value.has(name)
  }

  function toggleSelect(name: string, selected: boolean) {
    const next = new Set(selectedNames.value)
    if (selected) {
      next.add(name)
    } else {
      next.delete(name)
    }
    selectedNames.value = next
  }

  function toggleSelectAll(selected: boolean) {
    if (!selected) {
      clearSelection()
      return
    }
    selectedNames.value = new Set(entries.value.map(e => e.name))
  }

  const relativePath = computed(() => {
    const root = stagingRoot()
    const cur = currentPath.value
    if (!root || !cur || cur === root) return ''
    return cur.startsWith(`${root}/`) ? cur.slice(root.length + 1) : cur
  })

  async function refreshStagingStats() {
    const root = stagingRoot()
    if (!root || !uploadedSource.value) return
    try {
      const res = await http.post<ValidateSourcePathResponse>('/sync/validate-source-path', { path: root })
      uploadedSource.value = {
        ...uploadedSource.value,
        fileCount: res.file_count,
        size: res.size_bytes,
      }
    } catch {
      // Stats refresh is best-effort after file ops
    }
  }

  async function loadDirectory(path: string) {
    if (!path) {
      entries.value = []
      currentPath.value = ''
      return
    }
    loading.value = true
    try {
      const res = await http.post<BrowseLocalResponse>('/sync/browse-local', { path })
      currentPath.value = res.path
      entries.value = res.entries ?? []
      clearSelection()
    } catch (e: unknown) {
      entries.value = []
      snackbar(e instanceof Error ? e.message : '加载暂存目录失败', 'error')
    } finally {
      loading.value = false
    }
  }

  function goRoot() {
    void loadDirectory(stagingRoot())
  }

  function refreshCurrent() {
    void loadDirectory(currentPath.value || stagingRoot())
  }

  function openDirectory(entry: StagingEntry) {
    if (!entry.is_dir || !currentPath.value) return
    void loadDirectory(joinHostPath(currentPath.value, entry.name))
  }

  function openRename(entry: StagingEntry) {
    renameTarget.value = entry
    renameValue.value = entry.name
    renameOpen.value = true
  }

  async function confirmRename() {
    const entry = renameTarget.value
    const newName = renameValue.value.trim()
    if (!entry || !currentPath.value || !newName || newName === entry.name) {
      renameOpen.value = false
      return
    }
    renameLoading.value = true
    try {
      await http.post('/sync/local-file-ops', {
        operation: 'rename',
        path: joinHostPath(currentPath.value, entry.name),
        new_name: newName,
      })
      snackbar('已重命名')
      renameOpen.value = false
      await loadDirectory(currentPath.value)
      await refreshStagingStats()
    } catch (e: unknown) {
      snackbar(e instanceof Error ? e.message : '重命名失败', 'error')
    } finally {
      renameLoading.value = false
    }
  }

  function openDelete(entry: StagingEntry) {
    deleteTargets.value = [entry]
    deleteOpen.value = true
  }

  function openBatchDelete() {
    const targets = entries.value.filter(e => selectedNames.value.has(e.name))
    if (!targets.length) {
      snackbar('请先选择要删除的项', 'warning')
      return
    }
    deleteTargets.value = targets
    deleteOpen.value = true
  }

  async function confirmDelete() {
    const targets = deleteTargets.value
    if (!targets.length || !currentPath.value) {
      deleteOpen.value = false
      return
    }
    deleteLoading.value = true
    let ok = 0
    let fail = 0
    try {
      for (const entry of targets) {
        try {
          await http.post('/sync/local-file-ops', {
            operation: 'delete',
            path: joinHostPath(currentPath.value, entry.name),
          })
          ok++
        } catch {
          fail++
        }
      }
      deleteOpen.value = false
      clearSelection()
      await loadDirectory(currentPath.value)
      await refreshStagingStats()
      if (fail > 0) {
        snackbar(`已删除 ${ok} 项，${fail} 项失败`, 'warning')
      } else {
        snackbar(targets.length > 1 ? `已删除 ${ok} 项` : '已删除')
      }
    } finally {
      deleteLoading.value = false
    }
  }

  async function previewFile(entry: StagingEntry) {
    if (entry.is_dir || !currentPath.value) return
    previewOpen.value = true
    previewLoading.value = true
    previewResult.value = null
    try {
      previewResult.value = await http.post<StagingPreviewResult>('/sync/local-file-preview', {
        path: joinHostPath(currentPath.value, entry.name),
      })
    } catch (e: unknown) {
      previewOpen.value = false
      snackbar(e instanceof Error ? e.message : '预览失败', 'error')
    } finally {
      previewLoading.value = false
    }
  }

  watch(
    () => uploadedSource.value?.sourcePath,
    (path) => {
      if (path) {
        void loadDirectory(path)
      } else {
        entries.value = []
        currentPath.value = ''
        clearSelection()
      }
    },
    { immediate: true },
  )

  return {
    loading,
    currentPath,
    entries,
    relativePath,
    goRoot,
    refreshCurrent,
    openDirectory,
    loadDirectory,
    openRename,
    confirmRename,
    renameOpen,
    renameValue,
    renameLoading,
    renameTarget,
    openDelete,
    openBatchDelete,
    confirmDelete,
    deleteOpen,
    deleteLoading,
    deleteTargets,
    selectedCount,
    allSelected,
    someSelected,
    isSelected,
    toggleSelect,
    toggleSelectAll,
    clearSelection,
    previewFile,
    previewOpen,
    previewLoading,
    previewResult,
  }
}
