import { getAuthHeaders } from '@context-providers/auth-context-provider'

import { type RefObject, useCallback, useRef, useState } from 'react'
import { toast } from 'sonner'

import { APP_CONFIG } from '@lib/config'
import { downloadBlob, getFilenameFromContentDisposition } from '@lib/excel-download'

export type ExcelSortState = { field: string; direction: 'asc' | 'desc' }[]

export type UseExcelIoOptions = {
  model?: string
  filters?: Record<string, unknown>
  sort?: ExcelSortState
  onImportSuccess?: () => void
  showToasts?: boolean
}

export type UseExcelIoResult = {
  isExportingExcel: boolean
  isImportingExcel: boolean
  importInputRef: RefObject<HTMLInputElement | null>
  handleExportExcel: (args?: {
    model?: string
    filters?: Record<string, unknown>
    sort?: ExcelSortState
  }) => Promise<void>
  handleImportExcel: (file: File | null) => Promise<void>
  openImportDialog: () => void
}

export function useExcelIo(options: UseExcelIoOptions): UseExcelIoResult {
  const { model, filters, sort, onImportSuccess, showToasts = true } = options
  const [isExportingExcel, setIsExportingExcel] = useState(false)
  const [isImportingExcel, setIsImportingExcel] = useState(false)
  const importInputRef = useRef<HTMLInputElement | null>(null)

  const handleExportExcel = useCallback(
    async (args?: { model?: string; filters?: Record<string, unknown>; sort?: ExcelSortState }) => {
      const targetModel = args?.model ?? model
      const targetFilters = args?.filters ?? filters
      const targetSort = args?.sort ?? sort

      setIsExportingExcel(true)
      try {
        const params = new URLSearchParams()
        if (Object.keys(targetFilters ?? {}).length > 0) {
          params.set('filters', JSON.stringify(targetFilters))
        }
        if (targetSort && targetSort.length > 0) {
          params.set('sort', JSON.stringify(targetSort))
        }

        const query = params.toString()
        const path = targetModel ? `export/${targetModel}` : 'export/all'
        const endpoint = `${APP_CONFIG.apiURL}/excel-io/${path}${query ? `?${query}` : ''}`
        const response = await fetch(endpoint, {
          headers: getAuthHeaders(),
          credentials: 'include',
        })
        if (!response.ok) {
          throw new Error(await response.text())
        }

        const blob = await response.blob()
        const filename = getFilenameFromContentDisposition(
          response.headers.get('Content-Disposition'),
          targetModel ? `${targetModel}.xlsx` : 'all-models.xlsx',
        )
        downloadBlob(blob, filename)
        if (showToasts) {
          toast.success('Excel export completed')
        }
      } catch (error) {
        if (showToasts) {
          toast.error(`Excel export failed: ${String(error)}`)
        }
      } finally {
        setIsExportingExcel(false)
      }
    },
    [filters, model, showToasts, sort],
  )

  const handleImportExcel = useCallback(
    async (file: File | null) => {
      if (!file) {
        return
      }

      setIsImportingExcel(true)
      try {
        const formData = new FormData()
        formData.append('file', file)

        const response = await fetch(`${APP_CONFIG.apiURL}/excel-io/import`, {
          method: 'POST',
          body: formData,
          headers: getAuthHeaders(),
          credentials: 'include',
        })
        const payload = await response.json().catch(() => undefined)
        if (!response.ok || payload?.success !== true) {
          throw new Error(payload?.error ?? 'Import failed')
        }

        if (showToasts) {
          toast.success('Excel import completed')
        }
        onImportSuccess?.()
      } catch (error) {
        if (showToasts) {
          toast.error(`Excel import failed: ${String(error)}`)
        }
      } finally {
        setIsImportingExcel(false)
        if (importInputRef.current) {
          importInputRef.current.value = ''
        }
      }
    },
    [onImportSuccess, showToasts],
  )

  const openImportDialog = useCallback(() => {
    importInputRef.current?.click()
  }, [])

  return {
    isExportingExcel,
    isImportingExcel,
    importInputRef,
    handleExportExcel,
    handleImportExcel,
    openImportDialog,
  }
}
