import { createContext, useContext, useState, useCallback, ReactNode } from 'react'
import { klausurApi, Klausur, StudentKlausur } from '../services/api'

interface KlausurContextType {
  klausuren: Klausur[]
  currentKlausur: Klausur | null
  currentStudent: StudentKlausur | null
  loading: boolean
  error: string | null
  loadKlausuren: () => Promise<void>
  selectKlausur: (id: string, keepStudent?: boolean) => Promise<void>
  selectStudent: (id: string) => void
  setStudentById: (id: string) => void
  refreshAndSelectStudent: (klausurId: string, studentId: string) => Promise<void>
  createKlausur: (data: Partial<Klausur>) => Promise<Klausur>
  deleteKlausur: (id: string) => Promise<void>
  updateCriteria: (studentId: string, criterion: string, score: number) => Promise<void>
}

const KlausurContext = createContext<KlausurContextType | null>(null)

export function KlausurProvider({ children }: { children: ReactNode }) {
  const [klausuren, setKlausuren] = useState<Klausur[]>([])
  const [currentKlausur, setCurrentKlausur] = useState<Klausur | null>(null)
  const [currentStudent, setCurrentStudent] = useState<StudentKlausur | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const loadKlausuren = useCallback(async () => {
    setLoading(true)
    setError(null)
    try {
      const data = await klausurApi.listKlausuren()
      setKlausuren(data)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Failed to load Klausuren')
    } finally {
      setLoading(false)
    }
  }, [])

  const selectKlausur = useCallback(async (id: string, keepStudent = false) => {
    setLoading(true)
    setError(null)
    try {
      const klausur = await klausurApi.getKlausur(id)
      setCurrentKlausur(klausur)
      // Optionally keep the current student selection (for refresh after save)
      if (keepStudent && currentStudent) {
        const updatedStudent = klausur.students.find(s => s.id === currentStudent.id)
        setCurrentStudent(updatedStudent || null)
      } else if (!keepStudent) {
        setCurrentStudent(null)
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Failed to load Klausur')
    } finally {
      setLoading(false)
    }
  }, [currentStudent])

  const selectStudent = useCallback((id: string) => {
    if (!currentKlausur) return
    const student = currentKlausur.students.find(s => s.id === id)
    setCurrentStudent(student || null)
  }, [currentKlausur])

  // Set student directly by ID (for cases where we need to set before state updates)
  const setStudentById = useCallback((id: string) => {
    if (!currentKlausur) return
    const student = currentKlausur.students.find(s => s.id === id)
    if (student) {
      setCurrentStudent(student)
    }
  }, [currentKlausur])

  // Combined refresh and select - useful after upload
  const refreshAndSelectStudent = useCallback(async (klausurId: string, studentId: string) => {
    setLoading(true)
    setError(null)
    try {
      const klausur = await klausurApi.getKlausur(klausurId)
      setCurrentKlausur(klausur)
      const student = klausur.students.find(s => s.id === studentId)
      if (student) {
        setCurrentStudent(student)
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Failed to load Klausur')
    } finally {
      setLoading(false)
    }
  }, [])

  const createKlausur = useCallback(async (data: Partial<Klausur>) => {
    setLoading(true)
    setError(null)
    try {
      const klausur = await klausurApi.createKlausur(data)
      setKlausuren(prev => [...prev, klausur])
      return klausur
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Failed to create Klausur')
      throw e
    } finally {
      setLoading(false)
    }
  }, [])

  const deleteKlausur = useCallback(async (id: string) => {
    setLoading(true)
    setError(null)
    try {
      await klausurApi.deleteKlausur(id)
      setKlausuren(prev => prev.filter(k => k.id !== id))
      if (currentKlausur?.id === id) {
        setCurrentKlausur(null)
        setCurrentStudent(null)
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Failed to delete Klausur')
      throw e
    } finally {
      setLoading(false)
    }
  }, [currentKlausur])

  const updateCriteria = useCallback(async (studentId: string, criterion: string, score: number) => {
    try {
      const updated = await klausurApi.updateCriteria(studentId, criterion, score)
      if (currentKlausur) {
        setCurrentKlausur({
          ...currentKlausur,
          students: currentKlausur.students.map(s =>
            s.id === studentId ? updated : s
          )
        })
      }
      if (currentStudent?.id === studentId) {
        setCurrentStudent(updated)
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Failed to update criteria')
      throw e
    }
  }, [currentKlausur, currentStudent])

  return (
    <KlausurContext.Provider value={{
      klausuren,
      currentKlausur,
      currentStudent,
      loading,
      error,
      loadKlausuren,
      selectKlausur,
      selectStudent,
      setStudentById,
      refreshAndSelectStudent,
      createKlausur,
      deleteKlausur,
      updateCriteria
    }}>
      {children}
    </KlausurContext.Provider>
  )
}

export function useKlausur() {
  const context = useContext(KlausurContext)
  if (!context) {
    throw new Error('useKlausur must be used within a KlausurProvider')
  }
  return context
}
