import { useEffect, useMemo, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { useAuth } from '../../auth/AuthProvider'
import { fetchSchoolYears } from '../../api/schoolYears'
import {
  fetchCompetitionScoresIndex,
  fetchParentEnrollments,
  fetchScoreCardSelectableStudents,
  fetchStudentScoreCard,
} from '../../api/session'
import type { ScoreCardSelectableStudent } from '../../api/session'
import type { StudentScoreCardRow } from '../../api/types'
import {
  parseScoreSortLabel,
  rowsForYear,
  scoreForSemester,
  semesterHeaderLabel,
  sortSemesterKeys,
} from './scoreCardListUtils'
import { canonicalSchoolYearName } from '../../lib/schoolYearOptions'

const LS_CLASS = 'alrahma_teacher_score_card_class_section_id'
const LS_YEAR = 'alrahma_teacher_score_card_school_year'

function backHomePath(selectedRole: string | null): string {
  const r = (selectedRole ?? '').toLowerCase()
  if (r.includes('parent')) return '/app/parent/home'
  if (r.includes('teacher')) return '/app/teacher_dashboard'
  return '/app/home'
}

function isTeacherLikeRole(role: string | null): boolean {
  const r = (role ?? '').toLowerCase()
  return r.includes('teacher')
}

/**
 * CI `StudentController::scoreCardList` uses session `class_section_id` + `school_year`, or
 * `teacher_class` rows. We mirror that by passing query params to the API and by resolving the
 * active class from competition-scores index (same “active class” as other teacher flows).
 */
async function resolveTeacherScoreCardContext(searchParams: URLSearchParams): Promise<{
  classSectionId: number
  schoolYear: string | null
}> {
  const canonicalSchoolYear = await resolveDefaultSchoolYear()
  const fromUrlC = Number(searchParams.get('class_section_id') ?? '0')
  const fromUrlY = searchParams.get('school_year')?.trim() || null
  if (fromUrlC > 0) {
    return { classSectionId: fromUrlC, schoolYear: fromUrlY ?? canonicalSchoolYear }
  }
  try {
    const lsC = Number(localStorage.getItem(LS_CLASS) ?? '0')
    const lsY = localStorage.getItem(LS_YEAR)?.trim() || null
    if (lsC > 0) {
      return { classSectionId: lsC, schoolYear: fromUrlY ?? lsY ?? canonicalSchoolYear }
    }
  } catch {
    /* ignore */
  }
  try {
    const comp = await fetchCompetitionScoresIndex(null)
    const cid = Number(comp.activeClassId ?? 0)
    const sy =
      comp.schoolYear != null && String(comp.schoolYear).trim() !== '' ? String(comp.schoolYear).trim() : null
    if (cid > 0) {
      try {
        localStorage.setItem(LS_CLASS, String(cid))
        if (sy ?? canonicalSchoolYear) localStorage.setItem(LS_YEAR, sy ?? canonicalSchoolYear ?? '')
      } catch {
        /* ignore */
      }
      return { classSectionId: cid, schoolYear: sy ?? canonicalSchoolYear }
    }
  } catch {
    /* ignore */
  }
  return { classSectionId: 0, schoolYear: fromUrlY ?? canonicalSchoolYear }
}

function filterStudentsToClassSection(
  rows: ScoreCardSelectableStudent[],
  classSectionId: number,
): ScoreCardSelectableStudent[] {
  if (classSectionId <= 0) return rows
  const hasSectionHints = rows.some((s) => Array.isArray(s.class_section_ids) && s.class_section_ids.length > 0)
  if (!hasSectionHints) return rows
  return rows.filter((s) => (s.class_section_ids ?? []).includes(classSectionId))
}

async function resolveDefaultSchoolYear(): Promise<string | null> {
  try {
    const years = await fetchSchoolYears()
    const canonical = canonicalSchoolYearName(years)
    if (canonical) return canonical
  } catch {
    /* ignore */
  }
  try {
    const comp = await fetchCompetitionScoresIndex(null)
    const sy = comp.schoolYear != null && String(comp.schoolYear).trim() !== '' ? String(comp.schoolYear).trim() : null
    return sy
  } catch {
    return null
  }
}

export function StudentScoreCardListPage() {
  const { selectedRole } = useAuth()
  const [searchParams] = useSearchParams()
  const [students, setStudents] = useState<ScoreCardSelectableStudent[]>([])
  const [listSchoolYear, setListSchoolYear] = useState<string | null>(null)
  const [semesterKeys, setSemesterKeys] = useState<string[]>([])
  const [scoreTableYear, setScoreTableYear] = useState<string>('')
  const [scoreByStudent, setScoreByStudent] = useState<Record<number, Record<string, string>>>({})
  const [error, setError] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const [loadingScores, setLoadingScores] = useState(false)
  /** `school_id` | `student` | semester key (e.g. `fall`). */
  const [sortKey, setSortKey] = useState<string>('student')
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc')

  const backUrl = useMemo(() => backHomePath(selectedRole), [selectedRole])

  const sortedStudents = useMemo(() => {
    const list = [...students]
    const m = sortDir === 'asc' ? 1 : -1
    list.sort((a, b) => {
      if (sortKey === 'school_id') {
        return m * String(a.school_id ?? '').localeCompare(String(b.school_id ?? ''), undefined, { numeric: true })
      }
      if (sortKey === 'student') {
        const la = `${a.lastname ?? ''} ${a.firstname ?? ''}`.trim().toLowerCase()
        const lb = `${b.lastname ?? ''} ${b.firstname ?? ''}`.trim().toLowerCase()
        let c = la.localeCompare(lb)
        if (c === 0) c = String(a.firstname ?? '').localeCompare(String(b.firstname ?? ''))
        return m * c
      }
      const sa = scoreByStudent[a.id]?.[sortKey] ?? '—'
      const sb = scoreByStudent[b.id]?.[sortKey] ?? '—'
      const na = parseScoreSortLabel(sa)
      const nb = parseScoreSortLabel(sb)
      const aNaN = Number.isNaN(na)
      const bNaN = Number.isNaN(nb)
      if (aNaN && bNaN) {
        /* tie-break by name */
      } else if (aNaN) return m * 1
      else if (bNaN) return m * -1
      else if (na !== nb) return m * (na < nb ? -1 : 1)

      const la = `${a.lastname ?? ''} ${a.firstname ?? ''}`.trim().toLowerCase()
      const lb = `${b.lastname ?? ''} ${b.firstname ?? ''}`.trim().toLowerCase()
      return m * la.localeCompare(lb)
    })
    return list
  }, [students, sortKey, sortDir, scoreByStudent])

  function toggleSort(key: string): void {
    if (sortKey === key) {
      setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'))
    } else {
      setSortKey(key)
      setSortDir('asc')
    }
  }

  function sortIndicator(key: string): string {
    if (sortKey !== key) return ''
    return sortDir === 'asc' ? ' ▲' : ' ▼'
  }

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      const role = (selectedRole ?? '').toLowerCase()
      try {
        if (isTeacherLikeRole(selectedRole)) {
          const { classSectionId, schoolYear } = await resolveTeacherScoreCardContext(searchParams)
          if (cancelled) return
          if (classSectionId <= 0) {
            setStudents([])
            setListSchoolYear(null)
            setError(
              'No class section is selected for your teacher account. Open Competition Scores or another class tool first, or add ?class_section_id=…&school_year=… to this page’s URL (same as the legacy portal session).',
            )
            return
          }
          const data = await fetchScoreCardSelectableStudents({
            classSectionId,
            schoolYear,
          })
          if (cancelled) return
          const raw = data.students ?? []
          setStudents(filterStudentsToClassSection(raw, classSectionId))
          setListSchoolYear(schoolYear ?? (await resolveDefaultSchoolYear()))
          setError(null)
          return
        }

        const defaultYear = await resolveDefaultSchoolYear()
        if (cancelled) return

        const data = await fetchScoreCardSelectableStudents()
        if (cancelled) return
        setStudents(data.students ?? [])
        setListSchoolYear(defaultYear)
        setError(null)
      } catch {
        if (cancelled) return
        if (isTeacherLikeRole(selectedRole)) {
          setStudents([])
          setListSchoolYear(null)
          setSemesterKeys([])
          setScoreByStudent({})
          setError(
            'Unable to load students for your class. The API should accept ?class_section_id=…&school_year=… on GET /api/v1/students/score-card/selectable (same rules as legacy scoreCardList), or return class_section_ids on each student for filtering.',
          )
          return
        }
        if (role.includes('parent')) {
          try {
            const en = await fetchParentEnrollments(null)
            if (cancelled) return
            setStudents(
              (en.students ?? []).map((s) => ({
                id: s.id,
                school_id: (s as { school_id?: string }).school_id ?? null,
                firstname: s.firstname,
                lastname: s.lastname,
              })),
            )
            setListSchoolYear(await resolveDefaultSchoolYear())
            setError(null)
          } catch (e) {
            if (!cancelled) {
              setStudents([])
              setListSchoolYear(null)
              setError(e instanceof Error ? e.message : 'Unable to load students.')
            }
          }
        } else {
          setStudents([])
          setListSchoolYear(null)
          setError(
            'Unable to load the student list. Ask your administrator to enable GET /api/v1/students/score-card/selectable for your role.',
          )
        }
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [selectedRole, searchParams.toString()])

  useEffect(() => {
    if (students.length === 0) {
      setSemesterKeys([])
      setScoreByStudent({})
      setScoreTableYear('')
      setLoadingScores(false)
      return
    }
    let cancelled = false
    ;(async () => {
      setLoadingScores(true)
      try {
        const packs: { id: number; rows: StudentScoreCardRow[] }[] = await Promise.all(
          students.map(async (s) => {
            try {
              const d = await fetchStudentScoreCard(s.id)
              return { id: s.id, rows: d.rows ?? [] }
            } catch {
              return { id: s.id, rows: [] }
            }
          }),
        )
        if (cancelled) return

        let effectiveYear = listSchoolYear?.trim() ?? ''
        if (!effectiveYear) {
          const years = new Set<string>()
          for (const p of packs) {
            for (const r of p.rows) {
              const y = String(r.school_year ?? '').trim()
              if (y) years.add(y)
            }
          }
          effectiveYear = Array.from(years).sort().pop() ?? ''
        }

        const semSet = new Set<string>()
        for (const p of packs) {
          for (const r of rowsForYear(p.rows, effectiveYear || null)) {
            const sem = String(r.semester ?? '').trim().toLowerCase()
            if (sem) semSet.add(sem)
          }
        }
        let semesters = Array.from(semSet).sort(sortSemesterKeys)
        if (semesters.length === 0) {
          semesters = ['fall', 'spring']
        }

        const matrix: Record<number, Record<string, string>> = {}
        for (const p of packs) {
          matrix[p.id] = {}
          for (const sem of semesters) {
            matrix[p.id][sem] = scoreForSemester(p.rows, effectiveYear || null, sem)
          }
        }

        setSemesterKeys(semesters)
        setScoreByStudent(matrix)
        setScoreTableYear(effectiveYear)
      } finally {
        if (!cancelled) setLoadingScores(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [students, listSchoolYear])

  const yearLine = scoreTableYear ? `School year: ${scoreTableYear}` : 'School year: (all loaded years)'

  return (
    <div className="container-xxl py-4">
      <div className="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-3">
        <div>
          <h2 className="mb-0">Student Score Card</h2>
          <div className="text-muted small">{yearLine} — semester columns show semester score; open the full card from a cell.</div>
        </div>
        <Link className="btn btn-outline-secondary" to={backUrl}>
          Back
        </Link>
      </div>

      {loading ? <div className="text-muted small">Loading…</div> : null}
      {error ? <div className="alert alert-warning">{error}</div> : null}

      {!loading && students.length === 0 && !error ? (
        <div className="alert alert-warning">No students available for your account.</div>
      ) : null}

      {!loading && students.length > 0 ? (
        <div className="card shadow-sm">
          <div className="card-body table-responsive pt-2">
            {loadingScores ? <div className="text-muted small mb-2">Loading semester scores…</div> : null}
            <table className="table table-striped align-middle mb-0">
              <thead className="table-light">
                <tr>
                  <th scope="col" className="text-nowrap">
                    <button
                      type="button"
                      className="btn btn-link btn-sm text-dark fw-semibold p-0 text-decoration-none"
                      onClick={() => toggleSort('school_id')}
                    >
                      School ID
                      <span className="text-muted small">{sortIndicator('school_id')}</span>
                    </button>
                  </th>
                  <th scope="col" className="text-nowrap">
                    <button
                      type="button"
                      className="btn btn-link btn-sm text-dark fw-semibold p-0 text-decoration-none"
                      onClick={() => toggleSort('student')}
                    >
                      Student
                      <span className="text-muted small">{sortIndicator('student')}</span>
                    </button>
                  </th>
                  {semesterKeys.map((sem) => (
                    <th key={sem} className="text-center text-nowrap">
                      <button
                        type="button"
                        className="btn btn-link btn-sm text-dark fw-semibold p-0 text-decoration-none"
                        onClick={() => toggleSort(sem)}
                      >
                        {semesterHeaderLabel(sem)}
                        <span className="text-muted small">{sortIndicator(sem)}</span>
                      </button>
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {sortedStudents.map((stu) => {
                  const label = `${stu.firstname ?? ''} ${stu.lastname ?? ''}`.trim()
                  return (
                    <tr key={stu.id}>
                      <td>{stu.school_id ?? ''}</td>
                      <td>{label}</td>
                      {semesterKeys.map((sem) => {
                        const text = scoreByStudent[stu.id]?.[sem] ?? '—'
                        const sp = new URLSearchParams()
                        if (scoreTableYear) sp.set('school_year', scoreTableYear)
                        sp.set('semester', semesterHeaderLabel(sem))
                        const to = `/app/student/score-card/${stu.id}?${sp.toString()}`
                        return (
                          <td key={sem} className="text-center text-nowrap">
                            <Link className="btn btn-sm btn-outline-primary" to={to}>
                              {text}
                            </Link>
                          </td>
                        )
                      })}
                    </tr>
                  )
                })}
              </tbody>
            </table>
          </div>
        </div>
      ) : null}
    </div>
  )
}
