import React from 'react'
import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { queryDocument, queryDocumentStream, ingestDocument, listDocuments, listChunks, deleteDocument, deleteChunk, listPromptProfiles, getPromptProfile, activatePromptProfile, updatePrompt, updateAllPrompts, resetPrompts, exportProfile, importProfile, listQueryHistory, getQueryHistoryDetail, deleteQueryHistory, clearQueryHistory, getHistoryStats, uploadVideo } from './api'
import type { QueryRequest, QueryResponse, QueryStreamEvent, SourceMetadata, SubQuestionSources, IngestResponse, DocumentListResponse, ChunkInfo, DeleteResponse, PromptProfileListResponse, PromptSetResponse, PromptUpdateRequest, PromptBatchUpdateRequest, PromptActivateResponse, PromptStatusResponse, ProfileExportData, ProfileImportResponse, QueryHistoryList, QueryHistoryDetail, HistoryStats, HistoryDeleteResponse, VideoUploadResponse } from '../types'
import { useState, useCallback, useRef } from 'react'

export const queryClient = new QueryClient()

export const useQueryDocument = () => {
  return useMutation<QueryResponse, Error, QueryRequest>({
    mutationFn: queryDocument,
  })
}

export interface QueryStreamState {
  extractedQuestions: string[] | null
  answer: string | null
  sources: SourceMetadata[] | null
  subQuestionSources: SubQuestionSources[] | null
  phase: 'idle' | 'decomposing' | 'retrieving' | 'filtering' | 'generating' | 'completed' | 'error'
  historyId: number | null
  error: Error | null
}

export const useQueryDocumentStream = () => {
  const [state, setState] = useState<QueryStreamState>({
    extractedQuestions: null,
    answer: null,
    sources: null,
    subQuestionSources: null,
    phase: 'idle',
    historyId: null,
    error: null,
  })
  const abortRef = useRef<AbortController | null>(null)

  const mutate = useCallback(async (request: QueryRequest) => {
    setState({
      extractedQuestions: null,
      answer: null,
      sources: null,
      subQuestionSources: null,
      phase: 'decomposing',
      historyId: null,
      error: null,
    })

    abortRef.current = new AbortController()

    try {
      await queryDocumentStream(request, (event: QueryStreamEvent) => {
        switch (event.phase) {
          case 'decomposed':
            setState(prev => ({
              ...prev,
              extractedQuestions: event.extracted_questions ?? null,
              phase: 'retrieving',
            }))
            break
          case 'retrieving':
            setState(prev => ({ ...prev, phase: 'retrieving' }))
            break
          case 'filtering':
            setState(prev => ({ ...prev, phase: 'filtering' }))
            break
          case 'generating':
            setState(prev => ({ ...prev, phase: 'generating' }))
            break
          case 'generating_subquestion':
            setState(prev => ({ ...prev, phase: 'generating' }))
            break
          case 'completed':
            setState(prev => ({
              ...prev,
              answer: event.answer ?? null,
              sources: event.sources ?? null,
              subQuestionSources: event.sub_question_sources ?? null,
              phase: 'completed',
              historyId: (event as any).history_id ?? null,
            }))
            break
          case 'error':
            setState(prev => ({
              ...prev,
              phase: 'error',
              error: new Error(event.message ?? 'Unknown error'),
            }))
            break
        }
      }, abortRef.current.signal)
    } catch (err) {
      if (err instanceof Error && err.name === 'AbortError') {
        setState(prev => ({ ...prev, phase: 'idle' }))
        return
      }
      setState(prev => ({
        ...prev,
        phase: 'error',
        error: err instanceof Error ? err : new Error(String(err)),
      }))
    }
  }, [])

  const decomposeOnly = useCallback(async (request: QueryRequest) => {
    setState({
      extractedQuestions: null,
      answer: null,
      sources: null,
      subQuestionSources: null,
      phase: 'decomposing',
      historyId: null,
      error: null,
    })

    abortRef.current = new AbortController()

    try {
      await queryDocumentStream({ question: request.question, stop_after_decompose: true }, (event: QueryStreamEvent) => {
        switch (event.phase) {
          case 'decomposed':
            setState(prev => ({
              ...prev,
              extractedQuestions: event.extracted_questions ?? null,
              phase: 'retrieving',
            }))
            break
          case 'retrieving':
            setState(prev => ({ ...prev, phase: 'retrieving' }))
            break
          case 'filtering':
            setState(prev => ({ ...prev, phase: 'filtering' }))
            break
          case 'generating':
            setState(prev => ({ ...prev, phase: 'generating' }))
            break
          case 'generating_subquestion':
            setState(prev => ({ ...prev, phase: 'generating' }))
            break
          case 'completed':
            setState(prev => ({
              ...prev,
              answer: event.half_question ? null : (event.answer ?? null),
              sources: event.sources ?? null,
              subQuestionSources: event.sub_question_sources ?? null,
              phase: 'completed',
              historyId: (event as any).history_id ?? null,
            }))
            break
          case 'error':
            setState(prev => ({
              ...prev,
              phase: 'error',
              error: new Error(event.message ?? 'Unknown error'),
            }))
            break
        }
      }, abortRef.current.signal)
    } catch (err) {
      if (err instanceof Error && err.name === 'AbortError') {
        setState(prev => ({ ...prev, phase: 'idle' }))
        return
      }
      setState(prev => ({
        ...prev,
        phase: 'error',
        error: err instanceof Error ? err : new Error(String(err)),
      }))
    }
  }, [])

  const reset = useCallback(() => {
    abortRef.current?.abort()
    setState({
      extractedQuestions: null,
      answer: null,
      sources: null,
      subQuestionSources: null,
      phase: 'idle',
      historyId: null,
      error: null,
    })
  }, [])

  return { ...state, mutate, decomposeOnly, reset }
}

export const useIngestDocument = () => {
  return useMutation<IngestResponse, Error, File>({
    mutationFn: ingestDocument,
  })
}

export const useDocuments = () => {
  return useQuery<DocumentListResponse, Error>({
    queryKey: ['documents'],
    queryFn: listDocuments,
  })
}

export const useDocumentChunks = (documentId: string | null) => {
  return useQuery<ChunkInfo[], Error>({
    queryKey: ['documents', documentId, 'chunks'],
    queryFn: () => listChunks(documentId!),
    enabled: documentId !== null,
  })
}

export const useDeleteDocument = () => {
  const queryClient = useQueryClient()
  return useMutation<DeleteResponse, Error, string>({
    mutationFn: deleteDocument,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['documents'] })
    },
  })
}

export const useDeleteChunk = () => {
  const queryClient = useQueryClient()
  return useMutation<DeleteResponse, Error, string>({
    mutationFn: deleteChunk,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['documents'] })
    },
  })
}

export const usePromptProfiles = () => {
  return useQuery<PromptProfileListResponse, Error>({
    queryKey: ['prompts', 'profiles'],
    queryFn: listPromptProfiles,
  })
}

export const usePromptProfile = (name: string | null) => {
  return useQuery<PromptSetResponse, Error>({
    queryKey: ['prompts', 'profiles', name],
    queryFn: () => getPromptProfile(name!),
    enabled: name !== null,
  })
}

export const useActivateProfile = () => {
  const queryClient = useQueryClient()
  return useMutation<PromptActivateResponse, Error, string>({
    mutationFn: activatePromptProfile,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['prompts'] })
    },
  })
}

export const useUpdatePrompt = () => {
  const queryClient = useQueryClient()
  return useMutation<PromptStatusResponse, Error, { name: string; step: string; request: PromptUpdateRequest }>({
    mutationFn: ({ name, step, request }) => updatePrompt(name, step, request),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['prompts'] })
    },
  })
}

export const useUpdateAllPrompts = () => {
  const queryClient = useQueryClient()
  return useMutation<PromptStatusResponse, Error, { name: string; request: PromptBatchUpdateRequest }>({
    mutationFn: ({ name, request }) => updateAllPrompts(name, request),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['prompts'] })
    },
  })
}

export const useResetPrompts = () => {
  const queryClient = useQueryClient()
  return useMutation<PromptStatusResponse, Error, { name: string; step?: string }>({
    mutationFn: ({ name, step }) => resetPrompts(name, step),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['prompts'] })
    },
  })
}

export const useImportProfile = () => {
  const queryClient = useQueryClient()
  return useMutation<ProfileImportResponse, Error, { name: string; data: ProfileExportData }>({
    mutationFn: ({ name, data }) => importProfile(name, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['prompts'] })
    },
  })
}

export const useQueryHistoryList = (limit = 50, offset = 0) => {
  return useQuery<QueryHistoryList, Error>({
    queryKey: ['history', { limit, offset }],
    queryFn: () => listQueryHistory(limit, offset),
  })
}

export const useQueryHistoryDetail = (id: number | null) => {
  return useQuery<QueryHistoryDetail, Error>({
    queryKey: ['history', id],
    queryFn: () => getQueryHistoryDetail(id!),
    enabled: id !== null,
  })
}

export const useDeleteQueryHistory = () => {
  const queryClient = useQueryClient()
  return useMutation<HistoryDeleteResponse, Error, number>({
    mutationFn: deleteQueryHistory,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['history'] })
    },
  })
}

export const useClearQueryHistory = () => {
  const queryClient = useQueryClient()
  return useMutation<HistoryDeleteResponse, Error, void>({
    mutationFn: clearQueryHistory,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['history'] })
    },
  })
}

export const useHistoryStats = () => {
  return useQuery<HistoryStats, Error>({
    queryKey: ['history', 'stats'],
    queryFn: getHistoryStats,
  })
}

export const AppQueryProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}

export const useVideoUpload = () => {
  return useMutation<VideoUploadResponse, Error, { file: File; onProgress?: (pct: number) => void }>({
    mutationFn: ({ file, onProgress }) => uploadVideo(file, onProgress),
  })
}
