import { useCallback, useState } from "react"
import axios from "axios"
import { toast } from "sonner"

import { ENDPOINTS } from "@/constants/endpoints"
import { api } from "@/lib/api"
import i18n from "@/lib/i18n"

export type ReportExportFormat = "pdf" | "xlsx"

export type ReportPayload = {
  report_code: string
  title: string
  filters: Record<string, unknown>
  generated_at: string
  generated_by?: string | null
  summary: Record<string, unknown>
  rows: Record<string, unknown>[]
  totals: Record<string, unknown>
  raw?: Record<string, unknown>
}

type GenerateArgs = {
  endpoint: string
  params?: Record<string, string>
}

type ExportArgs = GenerateArgs & {
  reportCode: string
  format: ReportExportFormat
}

type WrappedError = {
  message?: string
  detail?: string
  data?: {
    field_errors?: Record<string, string[]>
    error_code?: string
  }
}

function unwrapReport(response: unknown): ReportPayload {
  if (response && typeof response === "object" && "success" in response) {
    const wrapped = response as { success?: boolean; data?: ReportPayload; message?: string }
    if (wrapped.success === false) {
      throw new Error(wrapped.message || i18n.t("hooks.useReports.error_generate", { defaultValue: "Unable to generate report" }))
    }
    if (wrapped.data) return wrapped.data
  }
  return response as ReportPayload
}

function formatFieldErrors(fieldErrors?: Record<string, string[]>) {
  if (!fieldErrors) return null
  const messages = Object.entries(fieldErrors).flatMap(([field, errors]) => {
    if (!Array.isArray(errors) || errors.length === 0) return []
    return errors.map((message) => `${field}: ${message}`)
  })
  return messages.length ? messages.join(" | ") : null
}

function getReportErrorMessage(err: unknown, fallback: string) {
  if (axios.isAxiosError<WrappedError>(err)) {
    const data = err.response?.data
    return formatFieldErrors(data?.data?.field_errors) || data?.message || data?.detail || err.message || fallback
  }
  return err instanceof Error ? err.message : fallback
}

function today() {
  return new Date().toISOString().slice(0, 10)
}

export function useReports() {
  const [report, setReport] = useState<ReportPayload | null>(null)
  const [isLoading, setIsLoading] = useState(false)
  const [exporting, setExporting] = useState<ReportExportFormat | null>(null)
  const [error, setError] = useState<string | null>(null)

  const generateReport = useCallback(async ({ endpoint, params }: GenerateArgs) => {
    setIsLoading(true)
    setError(null)
    try {
      const result = unwrapReport(await api.get(endpoint, { params }))
      setReport(result)
      return result
    } catch (err) {
      const message = getReportErrorMessage(err, i18n.t("hooks.useReports.error_generate", { defaultValue: "Unable to generate report" }))
      setError(message)
      setReport(null)
      throw new Error(message)
    } finally {
      setIsLoading(false)
    }
  }, [])

  const exportReport = useCallback(async ({ endpoint, params, reportCode, format }: ExportArgs) => {
    setExporting(format)
    setError(null)
    try {
      const response = await axios.get(endpoint, {
        baseURL: ENDPOINTS.BASE_URL,
        params: { ...(params || {}), format },
        responseType: "blob",
      })
      const url = URL.createObjectURL(response.data)
      const link = document.createElement("a")
      link.href = url
      link.download = `${reportCode}-${today()}.${format}`
      document.body.appendChild(link)
      link.click()
      link.remove()
      URL.revokeObjectURL(url)
      toast.success(i18n.t("hooks.useReports.export_success", { defaultValue: "Report exported" }))
    } catch (err) {
      const message = getReportErrorMessage(err, i18n.t("hooks.useReports.error_export", { defaultValue: "Unable to export report" }))
      setError(message)
      throw new Error(message)
    } finally {
      setExporting(null)
    }
  }, [])

  const clearReport = useCallback(() => {
    setReport(null)
    setError(null)
  }, [])

  return {
    report,
    isLoading,
    exporting,
    error,
    setError,
    generateReport,
    exportReport,
    clearReport,
  }
}
