import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import {
  filesApi,
  type FileCategory,
  type FileRecord,
  type FileUploadConfig,
} from '../api'
import { categoryContains, findCategory } from '../utils/fileTree'

const DEFAULT_CONFIG: FileUploadConfig = {
  allowed_extensions: [],
  max_upload_size_mb: 50,
}

export function useFiles() {
  const [categories, setCategories] = useState<FileCategory[]>([])
  const [files, setFiles] = useState<FileRecord[]>([])
  const [config, setConfig] = useState<FileUploadConfig>(DEFAULT_CONFIG)
  const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(null)
  const [loading, setLoading] = useState(false)
  const fileRequestId = useRef(0)

  const loadCategories = useCallback(async () => {
    const response = await filesApi.listCategories()
    setCategories(response.data)
    return response.data
  }, [])

  const loadFiles = useCallback(async (categoryId: string | null = null) => {
    const requestId = ++fileRequestId.current
    setLoading(true)
    try {
      const response = await filesApi.list(categoryId)
      if (requestId === fileRequestId.current) setFiles(response.data)
    } finally {
      if (requestId === fileRequestId.current) setLoading(false)
    }
  }, [])

  const loadConfig = useCallback(async () => {
    const response = await filesApi.getConfig()
    setConfig(response.data)
  }, [])

  useEffect(() => {
    void Promise.allSettled([loadCategories(), loadFiles(), loadConfig()])
  }, [loadCategories, loadConfig, loadFiles])

  const selectCategory = useCallback((categoryId: string | null) => {
    setSelectedCategoryId(categoryId)
    void loadFiles(categoryId)
  }, [loadFiles])

  const refresh = useCallback(async () => {
    await Promise.all([loadCategories(), loadFiles(selectedCategoryId), loadConfig()])
  }, [loadCategories, loadConfig, loadFiles, selectedCategoryId])

  const createCategory = useCallback(async (name: string, parentId?: string) => {
    await filesApi.createCategory({ name, parent_id: parentId })
    await loadCategories()
  }, [loadCategories])

  const renameCategory = useCallback(async (id: string, name: string) => {
    await filesApi.updateCategory(id, { name })
    await loadCategories()
  }, [loadCategories])

  const deleteCategory = useCallback(async (id: string) => {
    const deletedRoot = findCategory(categories, id)
    const resetsSelection = Boolean(
      selectedCategoryId && deletedRoot && categoryContains(deletedRoot, selectedCategoryId),
    )
    const nextCategoryId = resetsSelection ? null : selectedCategoryId

    await filesApi.deleteCategory(id)
    setSelectedCategoryId(nextCategoryId)
    await Promise.all([loadCategories(), loadFiles(nextCategoryId)])
  }, [categories, loadCategories, loadFiles, selectedCategoryId])

  const uploadFiles = useCallback(async (items: File[], categoryId: string | null) => {
    let succeeded = 0
    let failed = 0
    for (const file of items) {
      try {
        await filesApi.upload(file, categoryId)
        succeeded += 1
      } catch {
        failed += 1
      }
    }
    if (succeeded > 0) {
      setSelectedCategoryId(categoryId)
      await loadFiles(categoryId)
    }
    return { succeeded, failed }
  }, [loadFiles])

  const deleteFile = useCallback(async (id: string) => {
    await filesApi.delete(id)
    await loadFiles(selectedCategoryId)
  }, [loadFiles, selectedCategoryId])

  const downloadFile = useCallback(async (record: FileRecord) => {
    const response = await filesApi.download(record.id)
    const url = URL.createObjectURL(response.data)
    const anchor = document.createElement('a')
    anchor.href = url
    anchor.download = record.original_name
    document.body.appendChild(anchor)
    anchor.click()
    anchor.remove()
    URL.revokeObjectURL(url)
  }, [])

  const selectedCategoryName = useMemo(() => {
    if (!selectedCategoryId) return '全部文件'
    return findCategory(categories, selectedCategoryId)?.name ?? '全部文件'
  }, [categories, selectedCategoryId])

  return {
    categories,
    files,
    config,
    selectedCategoryId,
    selectedCategoryName,
    loading,
    selectCategory,
    refresh,
    createCategory,
    renameCategory,
    deleteCategory,
    uploadFiles,
    deleteFile,
    downloadFile,
  }
}
