import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from 'react'
import { useSearchParams } from 'react-router-dom'
import { fetchSchoolYears, type SchoolYearRecord } from '../api/schoolYears'
import { useAuth } from '../auth/AuthProvider'
import {
  clearSelectedSchoolYear,
  getStoredSelectedSchoolYearName,
  isCurrentSchoolYear,
  isReadOnlySchoolYear,
  storeSelectedSchoolYear,
} from '../lib/schoolYearSelection'

type SchoolYearContextValue = {
  schoolYears: SchoolYearRecord[]
  selectedSchoolYear: SchoolYearRecord | null
  selectedSchoolYearName: string | null
  activeSchoolYear: SchoolYearRecord | null
  isLoadingSchoolYears: boolean
  schoolYearError: string | null
  isReadOnlyYear: boolean
  setSelectedSchoolYearName: (name: string | null) => void
  refreshSchoolYears: () => Promise<void>
}

const SchoolYearContext = createContext<SchoolYearContextValue | null>(null)

function yearNameFromSearchParams(searchParams: URLSearchParams): string | null {
  return (
    searchParams.get('school_year')?.trim() ||
    searchParams.get('schoolYear')?.trim() ||
    null
  )
}

function resolveSelectedYear(params: {
  years: SchoolYearRecord[]
  searchParams: URLSearchParams
  requestedName: string | null
}): SchoolYearRecord | null {
  const { years, searchParams, requestedName } = params
  if (years.length === 0) return null

  const urlName = yearNameFromSearchParams(searchParams)
  const storedName = getStoredSelectedSchoolYearName()

  const byRequestedName = requestedName ? years.find((year) => year.name === requestedName) : null
  if (byRequestedName) return byRequestedName

  const byUrlName = urlName ? years.find((year) => year.name === urlName) : null
  if (byUrlName) return byUrlName

  const byStoredName = storedName ? years.find((year) => year.name === storedName) : null
  if (byStoredName) return byStoredName

  return years.find(isCurrentSchoolYear) ?? years[0] ?? null
}

export function SchoolYearProvider({ children }: { children: ReactNode }) {
  const { token } = useAuth()
  const [searchParams, setSearchParams] = useSearchParams()
  const [schoolYears, setSchoolYears] = useState<SchoolYearRecord[]>([])
  const [requestedYearName, setRequestedYearName] = useState<string | null>(null)
  const [isLoadingSchoolYears, setIsLoadingSchoolYears] = useState(false)
  const [schoolYearError, setSchoolYearError] = useState<string | null>(null)

  const refreshSchoolYears = useCallback(async () => {
    if (!token) {
      setSchoolYears([])
      setSchoolYearError(null)
      clearSelectedSchoolYear()
      return
    }

    setIsLoadingSchoolYears(true)
    setSchoolYearError(null)

    try {
      const years = await fetchSchoolYears()
      setSchoolYears(years)
    } catch (error) {
      setSchoolYears([])
      setSchoolYearError(error instanceof Error ? error.message : 'Unable to load school years.')
    } finally {
      setIsLoadingSchoolYears(false)
    }
  }, [token])

  useEffect(() => {
    void refreshSchoolYears()
  }, [refreshSchoolYears])

  const selectedSchoolYear = useMemo(
    () =>
      resolveSelectedYear({
        years: schoolYears,
        searchParams,
        requestedName: requestedYearName,
      }),
    [requestedYearName, schoolYears, searchParams],
  )

  const activeSchoolYear = useMemo(
    () => schoolYears.find(isCurrentSchoolYear) ?? null,
    [schoolYears],
  )

  useEffect(() => {
    storeSelectedSchoolYear(selectedSchoolYear)

    if (!selectedSchoolYear || !token) return

    setSearchParams((current) => {
      const next = new URLSearchParams(current)
      const currentName = next.get('school_year')

      next.delete('school_year_id')
      next.delete('year')

      if (currentName === selectedSchoolYear.name && next.toString() === current.toString()) {
        return current
      }

      next.set('school_year', selectedSchoolYear.name)
      return next
    }, { replace: true })
  }, [selectedSchoolYear, setSearchParams, token])

  const value = useMemo<SchoolYearContextValue>(() => ({
    schoolYears,
    selectedSchoolYear,
    selectedSchoolYearName: selectedSchoolYear?.name ?? null,
    activeSchoolYear,
    isLoadingSchoolYears,
    schoolYearError,
    isReadOnlyYear: isReadOnlySchoolYear(selectedSchoolYear),
    setSelectedSchoolYearName: setRequestedYearName,
    refreshSchoolYears,
  }), [
    activeSchoolYear,
    isLoadingSchoolYears,
    refreshSchoolYears,
    schoolYearError,
    schoolYears,
    selectedSchoolYear,
  ])

  return <SchoolYearContext.Provider value={value}>{children}</SchoolYearContext.Provider>
}

export function useSchoolYear(): SchoolYearContextValue {
  const context = useContext(SchoolYearContext)
  if (!context) {
    throw new Error('useSchoolYear must be used inside SchoolYearProvider.')
  }
  return context
}
