import { getAuthHeaders } from '@context-providers/auth-context-provider'
import type { ImportPreviewResponse } from '@excel-io/excel-io.service'
import type { ImportExecutionSummary } from '@import/import.service'
import { useMutation, useQueryClient } from '@tanstack/react-query'

import { useCallback, useState } from 'react'

import { APP_CONFIG } from '@lib/config'
import { useTRPC } from '@lib/trpc'

export type { ImportExecutionSummary } from '@import/import.service'
export type { ImportPreviewItem, ImportPreviewModelSummary, ImportPreviewResponse } from '@excel-io/excel-io.service'

type PreviewSessionResponse = {
  previewSessionId: string
}

export type ImportReviewStage = 'upload' | 'previewing' | 'review' | 'executing' | 'result'
export type SelectedDeltaIndicesByModel = Record<string, number[]>

export type UseImportReviewResult = {
  stage: ImportReviewStage
  preview: ImportPreviewResponse | null
  executionResult: ImportExecutionSummary | null
  error: string | null
  isLoading: boolean
  uploadAndPreview: (file: File, options: { includeDetailedUnchangedRecords: boolean }) => Promise<void>
  execute: (options: {
    ignoreErrors: boolean
    confirmDeletes: boolean
    selectedDeltaIndicesByModel: SelectedDeltaIndicesByModel
  }) => Promise<void>
  reset: () => void
}

export function useImportReview(): UseImportReviewResult {
  const trpc = useTRPC()
  const queryClient = useQueryClient()
  const [stage, setStage] = useState<ImportReviewStage>('upload')
  const [preview, setPreview] = useState<ImportPreviewResponse | null>(null)
  const [executionResult, setExecutionResult] = useState<ImportExecutionSummary | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [isLoading, setIsLoading] = useState(false)

  const executeMutation = useMutation(trpc.excelIo.execute.mutationOptions())

  const uploadAndPreview = useCallback(
    async (file: File, options: { includeDetailedUnchangedRecords: boolean }) => {
      setIsLoading(true)
      setError(null)
      setStage('previewing')

      try {
        const formData = new FormData()
        formData.append('file', file)
        formData.append('includeDetailedUnchangedRecords', String(options.includeDetailedUnchangedRecords))

        const response = await fetch(`${APP_CONFIG.apiURL}/excel-io/import/preview`, {
          method: 'POST',
          body: formData,
          headers: getAuthHeaders(),
          credentials: 'include',
        })

        const payload = (await response.json()) as {
          success: boolean
          result?: PreviewSessionResponse
          error?: string
        }

        if (!response.ok || !payload.success || !payload.result) {
          throw new Error(payload.error ?? 'Preview failed')
        }

        const previewResult = await queryClient.fetchQuery(
          trpc.excelIo.getPreview.queryOptions({ previewSessionId: payload.result.previewSessionId }),
        )

        setPreview(previewResult)
        setStage('review')
      } catch (err) {
        setError(err instanceof Error ? err.message : String(err))
        setStage('upload')
      } finally {
        setIsLoading(false)
      }
    },
    [queryClient, trpc.excelIo.getPreview],
  )

  const execute = useCallback(
    async (options: {
      ignoreErrors: boolean
      confirmDeletes: boolean
      selectedDeltaIndicesByModel: SelectedDeltaIndicesByModel
    }) => {
      if (!preview) {
        return
      }

      setIsLoading(true)
      setError(null)
      setStage('executing')

      try {
        const result = await executeMutation.mutateAsync({
          previewSessionId: preview.previewSessionId,
          ignoreErrors: options.ignoreErrors,
          confirmDeletes: options.confirmDeletes,
          selectedDeltaIndicesByModel: options.selectedDeltaIndicesByModel,
        })

        setExecutionResult(result)
        setStage('result')
      } catch (err) {
        setError(err instanceof Error ? err.message : String(err))
        setStage('review')
      } finally {
        setIsLoading(false)
      }
    },
    [executeMutation, preview],
  )

  const reset = useCallback(() => {
    setStage('upload')
    setPreview(null)
    setExecutionResult(null)
    setError(null)
    setIsLoading(false)
  }, [])

  return {
    stage,
    preview,
    executionResult,
    error,
    isLoading,
    uploadAndPreview,
    execute,
    reset,
  }
}
