import { type FormEvent, useEffect, useMemo, useState } from 'react'
import { Link, useLocation, useNavigate, useSearchParams } from 'react-router-dom'
import { ApiHttpError } from '../../api/http'
import { useSchoolYearOptions } from '../../hooks/useSchoolYearOptions'
import {
  fetchEnrollmentWithdrawalPage,
  postEnrollmentWithdrawalAssignClass,
  postEnrollmentWithdrawalStatusBatch,
  postGenerateInvoiceForParent,
} from '../../api/session'
import type {
  EnrollmentWithdrawalClassOption,
  EnrollmentWithdrawalStudentRow,
} from '../../api/types'
import {
  EnrollmentStatusBadge,
  NewStudentBadge,
  normStatus,
  RemovedPriorYearBadge,
} from './enrollmentStatusUi'
import './enrollWithdrawPages.css'

const STATUS_OPTIONS = [
  'admission under review',
  'payment pending',
  'enrolled',
  'withdraw under review',
  'refund pending',
  'withdrawn',
  'waitlist',
  'denied',
] as const

const SHOULD_INVOICE = new Set([
  'payment pending',
  'enrolled',
  'withdrawn',
  'refund pending',
  'withdraw under review',
])

function sidOf(row: EnrollmentWithdrawalStudentRow): number {
  return Number(row.student_id ?? row.id ?? 0)
}

function pidOf(row: EnrollmentWithdrawalStudentRow): number {
  return Number(row.parent_id ?? row.guardian_id ?? 0)
}

function formatRegistrationDate(raw?: string | null): string {
  if (raw == null || String(raw).trim() === '') return '-'
  const s = String(raw)
  const iso = /^(\d{4})-(\d{2})-(\d{2})/.exec(s)
  if (iso) return `${iso[2]}-${iso[3]}-${iso[1]}`
  const d = new Date(s)
  return Number.isNaN(d.getTime()) ? s : `${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}-${d.getFullYear()}`
}

function classOptionValue(c: EnrollmentWithdrawalClassOption): string {
  const v = c.class_section_id ?? c.id
  return v !== undefined && v !== null ? String(v) : ''
}

function classOptionLabel(c: EnrollmentWithdrawalClassOption): string {
  const label = String(c.class_section_name ?? c.name ?? '').trim()
  const id = classOptionValue(c)
  return label || `Section ${id}`
}

export function EnrollmentWithdrawalPage() {
  const navigate = useNavigate()
  const { pathname } = useLocation()
  const [searchParams] = useSearchParams()
  const schoolYearParam = searchParams.get('schoolYear') ?? ''
  const semesterParam = searchParams.get('semester') ?? ''

  const [rows, setRows] = useState<EnrollmentWithdrawalStudentRow[]>([])
  const [classes, setClasses] = useState<EnrollmentWithdrawalClassOption[]>([])
  const [schoolYears, setSchoolYears] = useState<string[]>([])
  const [selectedYear, setSelectedYear] = useState('')
  const [currentYear, setCurrentYear] = useState('')
  const [missingYear, setMissingYear] = useState(false)
  const [isCurrentYear, setIsCurrentYear] = useState(true)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [toast, setToast] = useState<{ ok: boolean; message: string } | null>(null)
  const [bulkWorking, setBulkWorking] = useState(false)

  /** Pending edits: undefined means “use row value”. */
  const [pendingStatus, setPendingStatus] = useState<Record<number, string>>({})
  const [pendingClass, setPendingClass] = useState<Record<number, string>>({})
  const { options, selectedYear: defaultYear } = useSchoolYearOptions({
    legacyYears: schoolYears,
    preferredYear: selectedYear || schoolYearParam,
  })

  const readOnly = missingYear || !isCurrentYear

  useEffect(() => {
    let cancelled = false
    setLoading(true)
    fetchEnrollmentWithdrawalPage({
      schoolYear: schoolYearParam || undefined,
      semester: semesterParam || undefined,
    })
      .then((d) => {
        if (cancelled) return
        setRows(d.students)
        setClasses(d.classes)
        setSchoolYears(d.schoolYears.length > 0 ? d.schoolYears : [])
        setSelectedYear(d.selectedYear)
        setCurrentYear(d.currentYear)
        setMissingYear(d.missingYear)
        setIsCurrentYear(d.isCurrentYear)
        setPendingStatus({})
        setPendingClass({})
        setError(null)
      })
      .catch((e: unknown) => {
        if (!cancelled)
          setError(e instanceof ApiHttpError ? e.message : 'Could not load enrollment data.')
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [schoolYearParam, semesterParam])

  useEffect(() => {
    if (!toast) return
    const t = window.setTimeout(() => setToast(null), 4000)
    return () => window.clearTimeout(t)
  }, [toast])

  const effectiveStatus = useMemo(() => {
    const out: Record<number, string> = {}
    for (const row of rows) {
      const sid = sidOf(row)
      if (!sid) continue
      const base = String(row.enrollment_status ?? '').trim()
      out[sid] = pendingStatus[sid] ?? base
    }
    return out
  }, [rows, pendingStatus])

  function onFilterSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault()
    const fd = new FormData(e.currentTarget)
    const sy = String(fd.get('schoolYear') ?? '')
    const sem = String(fd.get('semester') ?? '')
    const next = new URLSearchParams()
    if (sy) next.set('schoolYear', sy)
    if (sem) next.set('semester', sem)
    navigate({ pathname, search: next.toString() ? `?${next}` : '' })
  }

  async function onBulkSaveGenerate() {
    if (readOnly) return
    setBulkWorking(true)
    const errors: string[] = []
    const batchUpdates: { student_id: number; enrollment_status: string }[] = []
    const parentInvoice = new Set<number>()

    type Task = {
      studentId: number
      parentId: number
      classId: string
    }
    type StatusTask = { studentId: number; parentId: number; desired: string }

    const tasks: Task[] = []
    const statusTasks: StatusTask[] = []

    for (const row of rows) {
      const studentId = sidOf(row)
      const parentId = pidOf(row)
      if (!studentId) continue

      const prev = normStatus(row.enrollment_status ?? '')
      const desiredRaw = (pendingStatus[studentId] ?? String(row.enrollment_status ?? '')).trim()
      const desired = normStatus(desiredRaw)
      const classId = pendingClass[studentId] ?? ''

      const aur = normStatus('admission under review')
      const pp = normStatus('payment pending')
      const isAurToPp = prev === aur && desired === pp

      if (isAurToPp && classId) {
        tasks.push({ studentId, parentId, classId })
        continue
      }

      if (desired && desired !== prev) {
        if (isAurToPp && !classId) continue
        statusTasks.push({
          studentId,
          parentId,
          desired: desiredRaw.trim(),
        })
      }
    }

    if (tasks.length === 0 && statusTasks.length === 0) {
      setToast({
        ok: false,
        message:
          'Nothing to process. Set statuses as needed; for payment pending from admission under review, pick a class section.',
      })
      setBulkWorking(false)
      return
    }

    for (const t of tasks) {
      try {
        if (!t.parentId) throw new Error('Missing parent for student.')
        await postEnrollmentWithdrawalAssignClass({
          student_id: t.studentId,
          parent_id: t.parentId,
          class_section_id: t.classId,
        })
        batchUpdates.push({ student_id: t.studentId, enrollment_status: 'payment pending' })
        parentInvoice.add(t.parentId)
      } catch (e: unknown) {
        errors.push(
          `Assign class (student ${t.studentId}): ${e instanceof ApiHttpError ? e.message : String(e)}`,
        )
      }
    }

    for (const s of statusTasks) {
      batchUpdates.push({ student_id: s.studentId, enrollment_status: s.desired })
      const n = normStatus(s.desired)
      if (s.parentId && SHOULD_INVOICE.has(n)) parentInvoice.add(s.parentId)
    }

    const mergedByStudent = new Map<number, string>()
    for (const u of batchUpdates) mergedByStudent.set(u.student_id, u.enrollment_status)
    const deduped = [...mergedByStudent.entries()].map(([student_id, enrollment_status]) => ({
      student_id,
      enrollment_status,
    }))

    try {
      if (deduped.length > 0) {
        await postEnrollmentWithdrawalStatusBatch({
          updates: deduped,
          school_year: selectedYear || undefined,
          semester: semesterParam || undefined,
        })
      }
    } catch (e: unknown) {
      errors.push(e instanceof ApiHttpError ? e.message : 'Status update failed.')
    }

    for (const pid of parentInvoice) {
      if (!pid) continue
      try {
        await postGenerateInvoiceForParent(pid)
      } catch {
        /* non-fatal, mirrors legacy */
      }
    }

    try {
      const refreshed = await fetchEnrollmentWithdrawalPage({
        schoolYear: schoolYearParam || undefined,
        semester: semesterParam || undefined,
      })
      setRows(refreshed.students)
      setClasses(refreshed.classes)
      setSchoolYears(refreshed.schoolYears.length > 0 ? refreshed.schoolYears : [])
      setSelectedYear(refreshed.selectedYear)
      setCurrentYear(refreshed.currentYear)
      setMissingYear(refreshed.missingYear)
      setIsCurrentYear(refreshed.isCurrentYear)
      setPendingStatus({})
      setPendingClass({})
    } catch {
      /* ignore refresh failure */
    }

    if (errors.length > 0) setToast({ ok: false, message: errors[0] ?? 'Some updates failed.' })
    else setToast({ ok: true, message: 'Saved and invoices queued.' })

    setBulkWorking(false)
  }

  const yearSelectValue = schoolYearParam || selectedYear || defaultYear
  const semesterSelectValue = semesterParam

  return (
    <div className="container-fluid">
      <div className="wrapper">
        <div className="content" />
        <h2 className="text-center mt-4 mb-3">Manage Enrollment &amp; Withdrawal</h2>

        {missingYear ? (
          <div className="alert alert-warning d-flex align-items-center" role="alert">
            <div>
              Current school year is not configured. This page is read-only until configured in{' '}
              <Link to="/app/administrator/configuration_view" className="alert-link">
                Add/Edit Configuration
              </Link>{' '}
              (key: <code>school_year</code>).
            </div>
          </div>
        ) : null}

        {toast ? (
          <div className={`alert ${toast.ok ? 'alert-success' : 'alert-danger'}`} role="alert">
            {toast.message}
          </div>
        ) : null}

        <div className="row g-2 align-items-center justify-content-center mb-2">
          <div className="col-auto">
            <label htmlFor="schoolYearSelect" className="col-form-label">
              School year
            </label>
          </div>
          <div className="col-auto">
            <form className="d-flex align-items-center gap-2 flex-wrap" onSubmit={onFilterSubmit}>
              <select
                id="schoolYearSelect"
                name="schoolYear"
                className="form-select form-select-sm"
                style={{ minWidth: 180 }}
                defaultValue={yearSelectValue}
                key={`${yearSelectValue}-${semesterSelectValue}`}
              >
                {options.length > 0 ? (
                  options.map((option) => (
                    <option key={option.value} value={option.value}>
                      {option.label}
                    </option>
                  ))
                ) : (
                  <option value={yearSelectValue}>{yearSelectValue || '—'}</option>
                )}
              </select>
              <label htmlFor="ewSemester" className="col-form-label">
                Semester
              </label>
              <select
                id="ewSemester"
                name="semester"
                className="form-select form-select-sm"
                style={{ minWidth: 140 }}
                defaultValue={semesterSelectValue}
              >
                <option value="">—</option>
                <option value="Fall">Fall</option>
                <option value="Spring">Spring</option>
              </select>
              <button type="submit" className="btn btn-secondary btn-sm">
                Apply
              </button>
            </form>
          </div>
          {selectedYear && currentYear && selectedYear !== currentYear ? (
            <div className="col-auto">
              <span className="badge bg-secondary">Read-only (Past Year)</span>
            </div>
          ) : null}
        </div>

        {loading ? <p className="text-muted text-center">Loading…</p> : null}
        {!loading && error ? <div className="alert alert-danger">{error}</div> : null}

        <div className="table-responsive">
          <table className="table table-bordered table-striped mt-4 align-middle">
            <thead>
              <tr>
                <th>Registration Date</th>
                <th>Parent/Guardian</th>
                <th>Student Name</th>
                <th>New Student</th>
                <th>Removed (Prior Years)</th>
                <th>Current Class</th>
                <th>Actual Status</th>
                <th>Update Enrollment Status</th>
                <th>Assign Class</th>
              </tr>
            </thead>
            <tbody>
              {!loading && !error && rows.length === 0 ? (
                <tr>
                  <td colSpan={9}>No students available.</td>
                </tr>
              ) : null}
              {rows.map((student) => {
                const sid = sidOf(student)
                const pid = pidOf(student)
                const eff = normStatus(effectiveStatus[sid] ?? '')
                const base = String(student.enrollment_status ?? '').trim()
                const selectVal = pendingStatus[sid] ?? base
                const aur = normStatus('admission under review')
                const pending =
                  normStatus(selectVal) !== normStatus(base) ||
                  (eff === aur && (pendingClass[sid] ?? '') !== '')
                const showAssign = eff === aur
                const familyHref =
                  sid > 0 ? `/app/administrator/family?student_id=${encodeURIComponent(String(sid))}` : '#'

                return (
                  <tr key={sid || `${student.firstname}-${student.lastname}`} data-student-id={sid} data-parent-id={pid}>
                    <td>{formatRegistrationDate(student.registration_date)}</td>
                    <td>{student.parent_label ?? 'Unknown Parent'}</td>
                    <td>
                      {sid ? (
                        <Link to={familyHref} className="text-decoration-none">
                          {student.firstname ?? ''} {student.lastname ?? ''}
                        </Link>
                      ) : (
                        <>
                          {student.firstname ?? ''} {student.lastname ?? ''}
                        </>
                      )}
                    </td>
                    <td>
                      <NewStudentBadge value={student.new_student} />
                    </td>
                    <td>
                      <RemovedPriorYearBadge value={student.removed_previous_year} />
                    </td>
                    <td>{student.class_section ?? 'Class not Assigned'}</td>
                    <td>
                      <EnrollmentStatusBadge status={student.enrollment_status ?? 'not enrolled'} />
                    </td>
                    <td>
                      <select
                        className={`form-control enrollment-status form-select form-select-sm ${pending ? 'pending-status-select' : ''}`}
                        disabled={readOnly}
                        value={selectVal}
                        onChange={(e) => {
                          const v = e.target.value
                          setPendingStatus((p) => {
                            const next = { ...p, [sid]: v }
                            if (normStatus(v) === normStatus(student.enrollment_status ?? '')) {
                              delete next[sid]
                            }
                            return next
                          })
                          if (normStatus(v) !== aur) {
                            setPendingClass((c) => {
                              const next = { ...c }
                              delete next[sid]
                              return next
                            })
                          }
                        }}
                      >
                        {STATUS_OPTIONS.map((opt) => (
                          <option key={opt} value={opt}>
                            {opt}
                          </option>
                        ))}
                      </select>
                    </td>
                    <td>
                      {showAssign ? (
                        <select
                          className="form-select form-select-sm assign-class-select"
                          disabled={readOnly}
                          value={pendingClass[sid] ?? ''}
                          onChange={(e) =>
                            setPendingClass((c) => ({ ...c, [sid]: e.target.value }))
                          }
                        >
                          <option value="">— Select class section —</option>
                          {classes.map((cls) => {
                            const val = classOptionValue(cls)
                            if (!val) return null
                            return (
                              <option key={val} value={val}>
                                {classOptionLabel(cls)}
                              </option>
                            )
                          })}
                        </select>
                      ) : (
                        <span className="text-muted">—</span>
                      )}
                    </td>
                  </tr>
                )
              })}
            </tbody>
          </table>
        </div>

        <div className="d-flex justify-content-center gap-2 my-3 align-items-center">
          <button
            type="button"
            className="btn btn-success btn-lg"
            disabled={readOnly || bulkWorking}
            title={readOnly ? 'Editing disabled for non-current year or missing configuration.' : undefined}
            onClick={() => void onBulkSaveGenerate()}
          >
            Save &amp; Generate Invoice
          </button>
          {bulkWorking ? <span className="small text-muted">Processing…</span> : null}
        </div>
      </div>
    </div>
  )
}
