import { ref, computed, watch } from 'vue'
import { http } from '@/api'
import { useSnackbar } from '@/composables/useSnackbar'
import type { PushServerItem, SyncMode, UploadedSource, ValidatedSource } from './types'

type StagingUploadResponse = {
  source_path: string
  file_count: number
  size: number
  files?: string[]
}

type ValidateSourcePathResponse = {
  valid: boolean
  path: string
  file_count: number
  size_bytes: number
}

export function usePushForm() {
  const snackbar = useSnackbar()

  const sourcePath = ref('')
  const validatedSource = ref<ValidatedSource | null>(null)
  const lastValidatedPath = ref('')
  const sourcePathValidating = ref(false)
  /** 留空 = 使用各服务器在「服务器管理」中配置的 target_path */
  const targetPath = ref('')
  const syncMode = ref<SyncMode>('incremental')

  const isDragging = ref(false)
  const uploadedSource = ref<UploadedSource | null>(null)
  const sourceUploading = ref(false)

  watch(sourcePath, (v) => {
    if (validatedSource.value && v.trim() !== lastValidatedPath.value) {
      validatedSource.value = null
    }
  })

  const syncModeDesc = computed(() => {
    switch (syncMode.value) {
      case 'incremental':
        return '仅传输新增或修改的文件'
      case 'full':
        return '使目标目录与源目录完全一致，会删除不存在于源的文件'
      case 'checksum':
        return '通过文件内容校验和判断是否需要传输'
      default:
        return ''
    }
  })

  function effectiveSourcePath(): string {
    return uploadedSource.value?.sourcePath || validatedSource.value?.path || ''
  }

  /** 留空时后端按各服务器 target_path 推送 */
  function effectiveTargetPath(): string | undefined {
    const trimmed = targetPath.value.trim()
    return trimmed || undefined
  }

  function validateForm(selectedCount: number, selectedServers: PushServerItem[] = []): boolean {
    if (!effectiveSourcePath()) {
      if (sourcePath.value.trim() && !validatedSource.value) {
        snackbar('请先点击「验证路径」确认 Nexus 主机上的源目录', 'warning')
      } else {
        snackbar('请上传文件或验证 Nexus 主机源路径', 'warning')
      }
      return false
    }
    if (!effectiveTargetPath()) {
      const missing = selectedServers.filter(s => !(s.target_path || '').trim())
      if (missing.length > 0) {
        snackbar(
          '目标路径留空时，所选服务器须已在「服务器管理」中配置目标路径',
          'warning',
        )
        return false
      }
    }
    if (selectedCount === 0) {
      snackbar('请选择至少一台服务器', 'warning')
      return false
    }
    return true
  }

  async function validateSourcePath() {
    const p = sourcePath.value.trim()
    if (!p) {
      snackbar('请输入 Nexus 主机上的源目录路径', 'warning')
      return
    }
    if (uploadedSource.value) {
      snackbar('请先清除已上传的源文件', 'warning')
      return
    }

    sourcePathValidating.value = true
    try {
      const res = await http.post<ValidateSourcePathResponse>('/sync/validate-source-path', { path: p })
      validatedSource.value = {
        path: res.path,
        fileCount: res.file_count,
        sizeBytes: res.size_bytes,
      }
      lastValidatedPath.value = res.path
      sourcePath.value = res.path
      snackbar(`路径验证通过：${res.file_count} 个文件`)
    } catch (e: unknown) {
      validatedSource.value = null
      snackbar(e instanceof Error ? e.message : '路径验证失败', 'error')
    } finally {
      sourcePathValidating.value = false
    }
  }

  function clearValidatedSource() {
    validatedSource.value = null
    lastValidatedPath.value = ''
    sourcePath.value = ''
  }

  function clearUploadedSource() {
    uploadedSource.value = null
  }

  async function ingestSelectedFiles(files: File[]) {
    if (!files.length) return
    if (validatedSource.value) {
      snackbar('请先清除已验证的源路径', 'warning')
      return
    }
    await uploadPlainFiles(files)
  }

  async function handleFileDrop(e: DragEvent) {
    isDragging.value = false
    const files = Array.from(e.dataTransfer?.files ?? [])
    await ingestSelectedFiles(files)
  }

  function handleFileSelect(e: Event) {
    const input = e.target as HTMLInputElement
    const files = Array.from(input.files ?? [])
    input.value = ''
    void ingestSelectedFiles(files)
  }

  function handleZipExtractSelect(e: Event) {
    const input = e.target as HTMLInputElement
    const file = input.files?.[0]
    input.value = ''
    if (file) void uploadZipExtract(file)
  }

  async function uploadZipExtract(file: File) {
    if (validatedSource.value) {
      snackbar('请先清除已验证的源路径', 'warning')
      return
    }

    sourceUploading.value = true
    try {
      const form = new FormData()
      form.append('file', file)
      const res = await http.upload<StagingUploadResponse>('/sync/upload-zip', form)
      uploadedSource.value = {
        kind: 'zip',
        name: file.name,
        sourcePath: res.source_path,
        fileCount: res.file_count,
        size: res.size,
      }
      snackbar('ZIP 已解压到暂存目录')
    } catch (e: unknown) {
      snackbar(e instanceof Error ? e.message : 'ZIP 解压失败', 'error')
    } finally {
      sourceUploading.value = false
    }
  }

  async function uploadPlainFiles(files: File[]) {
    if (!files.length) return

    sourceUploading.value = true
    try {
      const form = new FormData()
      for (const f of files) {
        form.append('files', f)
      }
      const res = await http.upload<StagingUploadResponse>('/sync/upload-files', form)
      const displayName =
        files.length === 1
          ? files[0].name
          : `${files.length} 个文件`
      uploadedSource.value = {
        kind: 'files',
        name: displayName,
        sourcePath: res.source_path,
        fileCount: res.file_count,
        size: res.size,
      }
      snackbar(`已上传 ${res.file_count} 个文件`)
    } catch (e: unknown) {
      snackbar(e instanceof Error ? e.message : '上传失败', 'error')
    } finally {
      sourceUploading.value = false
    }
  }

  return {
    sourcePath,
    validatedSource,
    sourcePathValidating,
    targetPath,
    syncMode,
    syncModeDesc,
    isDragging,
    uploadedSource,
    sourceUploading,
    effectiveSourcePath,
    effectiveTargetPath,
    validateForm,
    validateSourcePath,
    clearValidatedSource,
    clearUploadedSource,
    handleFileDrop,
    handleFileSelect,
    handleZipExtractSelect,
  }
}
