import { type FormEvent, useEffect, useMemo, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { ApiHttpError } from '../../api/http'
import { fetchParticipation, postParticipation } from '../../api/grading'
import { useSchoolYearOptions } from '../../hooks/useSchoolYearOptions'
import { GRADING_PATH } from './gradingPaths'

/** CI `grading/participation.php` */
function normalizeParticipationScore(value: unknown): number | string | null {
  return typeof value === 'number' || typeof value === 'string' ? value : null
}

export function ParticipationPage() {
  const [searchParams] = useSearchParams()
  const requestedSchoolYear = searchParams.get('school_year') ?? ''
  const { selectedYear } = useSchoolYearOptions({
    preferredYear: requestedSchoolYear,
  })
  const [rows, setRows] = useState<
    Array<{
      student_id: number
      school_id?: string | null
      firstname?: string | null
      lastname?: string | null
      score?: number | string | null
    }>
  >([])
  const [locked, setLocked] = useState(false)
  const [title] = useState('Participation Scores')
  const [sectionName, setSectionName] = useState('')
  const [semester, setSemester] = useState(searchParams.get('semester') ?? '')
  const [schoolYear, setSchoolYear] = useState(requestedSchoolYear || selectedYear)
  const [loading, setLoading] = useState(true)
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [tableSearch, setTableSearch] = useState('')

  const classSectionId = searchParams.get('class_section_id') ?? ''
  const effectiveSchoolYear = schoolYear || selectedYear
  const participationSearchParams = useMemo(() => {
    const next = new URLSearchParams(searchParams)
    if (effectiveSchoolYear) next.set('school_year', effectiveSchoolYear)
    return next
  }, [effectiveSchoolYear, searchParams])

  useEffect(() => {
    let c = false
    setLoading(true)
    fetchParticipation(participationSearchParams)
      .then((p) => {
        if (c) return
        if (p && typeof p === 'object') {
          const o = p as Record<string, unknown>
          const students = Array.isArray(o.students) ? o.students : []
          setRows(
            students.map((row) => {
              const student = row as Record<string, unknown>
              const scores = (student.scores ?? {}) as Record<string, unknown>
              return {
                student_id: Number(student.student_id ?? 0),
                school_id: typeof student.school_id === 'string' ? student.school_id : null,
                firstname: typeof student.firstname === 'string' ? student.firstname : null,
                lastname: typeof student.lastname === 'string' ? student.lastname : null,
                score: normalizeParticipationScore(scores.score),
              }
            }),
          )
          setLocked(Boolean(o.scores_locked ?? o.scoresLocked ?? o.locked))
          setSectionName(typeof o.class_section_name === 'string' ? o.class_section_name : '')
          setSemester(typeof o.semester === 'string' ? o.semester : (searchParams.get('semester') ?? ''))
          setSchoolYear(
            typeof o.school_year === 'string' && o.school_year.trim() !== ''
              ? o.school_year
              : effectiveSchoolYear,
          )
        }
        setError(null)
      })
      .catch((e: unknown) => {
        if (!c) setError(e instanceof ApiHttpError ? e.message : 'Unable to load participation.')
      })
      .finally(() => {
        if (!c) setLoading(false)
      })
    return () => {
      c = true
    }
  }, [effectiveSchoolYear, participationSearchParams, searchParams])

  const visibleRows = useMemo(() => {
    const normalized = tableSearch.toLowerCase().trim()
    if (normalized === '') return rows
    return rows.filter((row) =>
      `${row.school_id ?? ''} ${row.firstname ?? ''} ${row.lastname ?? ''}`.toLowerCase().includes(normalized),
    )
  }, [rows, tableSearch])

  function setScore(i: number, value: string) {
    setRows((prev) => {
      const next = [...prev]
      next[i] = { ...next[i], score: value === '' ? null : Number(value) }
      return next
    })
  }

  async function onSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault()
    setSaving(true)
    setError(null)
    try {
      const body: Record<string, unknown> = {
        class_section_id: classSectionId ? Number(classSectionId) : undefined,
        school_year: effectiveSchoolYear || undefined,
        semester: semester || undefined,
        scores: rows.reduce<Record<string, { score: number | string | null }>>((carry, row) => {
          carry[String(row.student_id)] = { score: row.score ?? '' }
          return carry
        }, {}),
      }
      await postParticipation(body)
      const next = await fetchParticipation(participationSearchParams)
      if (next && typeof next === 'object') {
        const o = next as Record<string, unknown>
        const students = Array.isArray(o.students) ? o.students : []
        setRows(
          students.map((row) => {
            const student = row as Record<string, unknown>
            const scores = (student.scores ?? {}) as Record<string, unknown>
            return {
              student_id: Number(student.student_id ?? 0),
              school_id: typeof student.school_id === 'string' ? student.school_id : null,
              firstname: typeof student.firstname === 'string' ? student.firstname : null,
              lastname: typeof student.lastname === 'string' ? student.lastname : null,
              score: normalizeParticipationScore(scores.score),
            }
          }),
        )
      }
    } catch (err: unknown) {
      setError(err instanceof ApiHttpError ? err.message : 'Save failed.')
    } finally {
      setSaving(false)
    }
  }

  const qs = searchParams.toString()

  return (
    <div className="container mt-5">
      <h2 className="text-center mb-4">{title}</h2>
      <p className="text-center text-muted small">
        {(sectionName || (classSectionId ? `Section ${classSectionId}` : 'Section'))} • {semester || '—'} • {schoolYear || '—'}
      </p>

      <div className="mb-3">
        <Link className="btn btn-outline-secondary btn-sm" to={`${GRADING_PATH}${qs ? `?${qs}` : ''}`}>
          Grading hub
        </Link>
      </div>

      {locked ? (
        <div className="alert alert-warning">Scores are locked for this selection.</div>
      ) : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? <p className="text-muted">Loading…</p> : null}

      {!loading && rows.length > 0 ? (
        <form onSubmit={(ev) => void onSubmit(ev)}>
          <div className="d-flex flex-wrap justify-content-between align-items-center gap-3 mb-3">
            <div className="d-flex align-items-center gap-2">
              <span>Show</span>
              <select className="form-select form-select-sm" style={{ width: 78 }} defaultValue="100" disabled>
                <option value="100">100</option>
              </select>
              <span>entries</span>
            </div>
            <div className="d-flex align-items-center gap-2">
              <label className="mb-0">Search:</label>
              <input
                className="form-control form-control-sm"
                style={{ width: 220 }}
                value={tableSearch}
                onChange={(event) => setTableSearch(event.target.value)}
              />
            </div>
          </div>

          <div className="table-responsive">
            <table className="table table-bordered table-striped align-middle">
              <thead className="table-light">
                <tr>
                  <th>#</th>
                  <th>School ID</th>
                  <th>First Name</th>
                  <th>Last Name</th>
                  <th className="text-center">Score</th>
                </tr>
              </thead>
              <tbody>
                {visibleRows.map((row, i) => (
                  <tr key={row.student_id}>
                    <td>{i + 1}</td>
                    <td>{row.school_id ?? '—'}</td>
                    <td>{row.firstname ?? '—'}</td>
                    <td>{row.lastname ?? '—'}</td>
                    <td>
                      <input
                        type="number"
                        min="0"
                        max="100"
                        step="0.01"
                        className="form-control text-center"
                        disabled={locked}
                        value={row.score ?? ''}
                        onChange={(ev) => {
                          const originalIndex = rows.findIndex((candidate) => candidate.student_id === row.student_id)
                          if (originalIndex >= 0) setScore(originalIndex, ev.target.value)
                        }}
                      />
                    </td>
                  </tr>
                ))}
                {visibleRows.length === 0 ? (
                  <tr>
                    <td colSpan={5} className="text-muted text-center">
                      No students match the current search.
                    </td>
                  </tr>
                ) : null}
              </tbody>
            </table>
          </div>
          <div className="text-center mt-3">
            <button type="submit" className="btn btn-primary" disabled={locked || saving}>
              {saving ? 'Saving…' : 'Save Changes'}
            </button>
          </div>
        </form>
      ) : null}

      {!loading && rows.length === 0 ? (
        <div className="alert alert-light border">No students for this filter.</div>
      ) : null}
    </div>
  )
}
