import { type FormEvent, useEffect, useMemo, useState } from 'react'
import { Link, useParams, useSearchParams } from 'react-router-dom'
import { ApiHttpError } from '../../api/http'
import {
  fetchGradingSectionScoreTable,
  fetchGradingScoreForm,
  postGradingSectionScoreUpdate,
  postGradingScoreUpdate,
  type GradingSectionScorePayload,
  type GradingSectionScoreStudent,
  type GradingScoreFormPayload,
  type GradingScoreRow,
} from '../../api/grading'
import { isGradingScoreType } from './gradingScoreTypes'
import { GRADING_PATH } from './gradingPaths'

/** CI `grading/test.php`, `homework.php`, `quiz.php`, `project.php`, `midterm.php`, `final.php`, `comments.php`. */
export function GradingScoreEntryPage() {
  const { scoreType = '', classSectionId = '', studentId = '' } = useParams()
  const [searchParams] = useSearchParams()
  const semester = searchParams.get('semester') ?? ''
  const schoolYear = searchParams.get('school_year') ?? ''

  const [data, setData] = useState<GradingScoreFormPayload | null>(null)
  const [sectionData, setSectionData] = useState<GradingSectionScorePayload | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [saving, setSaving] = useState(false)

  const [scoreRows, setScoreRows] = useState<GradingScoreRow[]>([])
  const [singleScore, setSingleScore] = useState('')
  const [generalComment, setGeneralComment] = useState('')
  const [sectionRows, setSectionRows] = useState<GradingSectionScoreStudent[]>([])
  const [tableSearch, setTableSearch] = useState('')

  const isSectionMode = studentId === ''
  const resolvedSemester = sectionData?.semester ?? semester
  const resolvedSchoolYear = sectionData?.school_year ?? schoolYear
  const resolvedSectionName = (sectionData?.class_section_name ?? data?.class_section_name ?? '').trim()

  function sectionQuery() {
    const query = new URLSearchParams()
    if (semester !== '') query.set('semester', semester)
    if (schoolYear !== '') query.set('school_year', schoolYear)
    return query
  }

  useEffect(() => {
    if (!isGradingScoreType(scoreType) || !studentId || !classSectionId || !semester || !schoolYear) {
      if (!isSectionMode || !isGradingScoreType(scoreType) || !classSectionId) {
        setLoading(false)
        setData(null)
        setSectionData(null)
        return
      }
    }
    let c = false
    setLoading(true)
    if (isSectionMode) {
      fetchGradingSectionScoreTable(scoreType, classSectionId, sectionQuery())
        .then((payload) => {
          if (c) return
          setSectionData(payload)
          setSectionRows(Array.isArray(payload.students) ? payload.students.map((row) => ({ ...row })) : [])
          setData(null)
          setError(null)
        })
        .catch((e: unknown) => {
          if (!c) setError(e instanceof ApiHttpError ? e.message : 'Unable to load score table.')
        })
        .finally(() => {
          if (!c) setLoading(false)
        })
    } else {
      fetchGradingScoreForm(scoreType, classSectionId, studentId, sectionQuery())
        .then((p) => {
          if (c) return
          setData(p)
          setScoreRows(Array.isArray(p.scores) ? [...p.scores] : [])
          const first = p.scores?.[0]
          setSingleScore(first?.score !== undefined && first?.score !== null ? String(first.score) : '')
          setGeneralComment(first?.comment != null ? String(first.comment) : '')
          setSectionData(null)
          setError(null)
        })
        .catch((e: unknown) => {
          if (!c) setError(e instanceof ApiHttpError ? e.message : 'Unable to load score form.')
        })
        .finally(() => {
          if (!c) setLoading(false)
        })
    }
    return () => {
      c = true
    }
  }, [classSectionId, isSectionMode, schoolYear, scoreType, semester, studentId])

  const title =
    scoreType === 'homework'
      ? 'Homework'
      : scoreType === 'quiz'
        ? 'Quiz'
        : scoreType === 'project'
          ? 'Project'
          : scoreType === 'test'
            ? 'Test'
            : scoreType === 'midterm'
              ? 'Midterm Exam'
              : scoreType === 'final'
                ? 'Final Exam'
                : scoreType === 'comments'
                  ? 'General Comments'
                  : 'Scores'

  const locked = Boolean(data?.scoresLocked)
  const sectionLocked = Boolean(sectionData?.scores_locked)
  const student = data?.student
  const name =
    student?.firstname || student?.lastname
      ? `${student?.firstname ?? ''} ${student?.lastname ?? ''}`.trim()
      : 'Student'
  const studentSchoolId = student?.school_id ?? null

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

  const sectionHeaders = sectionData?.headers ?? []

  function updateSectionScore(studentIdValue: number, key: string, value: string) {
    setSectionRows((current) =>
      current.map((row) =>
        row.student_id === studentIdValue
          ? {
              ...row,
              scores: {
                ...(row.scores ?? {}),
                [key]: value,
              },
            }
          : row,
      ),
    )
  }

  function updateSectionExamScore(studentIdValue: number, value: string) {
    setSectionRows((current) =>
      current.map((row) => (row.student_id === studentIdValue ? { ...row, score: value } : row)),
    )
  }

  function updateSectionComment(
    studentIdValue: number,
    key: string,
    field: 'comment' | 'comment_review',
    value: string,
  ) {
    setSectionRows((current) =>
      current.map((row) =>
        row.student_id === studentIdValue
          ? {
              ...row,
              comments: {
                ...(row.comments ?? {}),
                [key]: {
                  ...(row.comments?.[key] ?? {}),
                  [field]: value,
                },
              },
            }
          : row,
      ),
    )
  }

  async function onSubmit(e: FormEvent) {
    e.preventDefault()
    if (isSectionMode) {
      if (!isGradingScoreType(scoreType) || !classSectionId || !resolvedSemester || !resolvedSchoolYear) return
      setSaving(true)
      setError(null)
      try {
        let body: Record<string, unknown> = {
          class_section_id: Number(classSectionId),
          semester: resolvedSemester,
          school_year: resolvedSchoolYear,
        }

        if (['homework', 'quiz', 'project'].includes(scoreType)) {
          const scores: Record<string, Record<string, number | string | null>> = {}
          for (const row of sectionRows) {
            scores[String(row.student_id)] = {}
            for (const header of sectionHeaders) {
              scores[String(row.student_id)][String(header)] = row.scores?.[String(header)] ?? ''
            }
          }
          body = { ...body, scores }
        } else if (['midterm', 'final'].includes(scoreType)) {
          const scores: Record<string, { score: number | string | null }> = {}
          for (const row of sectionRows) {
            scores[String(row.student_id)] = { score: row.score ?? '' }
          }
          body = { ...body, scores }
        } else if (scoreType === 'comments') {
          const comments: Record<string, Record<string, string>> = {}
          const reviews: Record<string, Record<string, string>> = {}
          for (const row of sectionRows) {
            comments[String(row.student_id)] = {}
            reviews[String(row.student_id)] = {}
            for (const [commentType, commentData] of Object.entries(row.comments ?? {})) {
              comments[String(row.student_id)][commentType] = commentData?.comment ?? ''
              reviews[String(row.student_id)][commentType] = commentData?.comment_review ?? ''
            }
          }
          body = { ...body, comments, reviews }
        }

        await postGradingSectionScoreUpdate(scoreType, body)
        const next = await fetchGradingSectionScoreTable(scoreType, classSectionId, sectionQuery())
        setSectionData(next)
        setSectionRows(Array.isArray(next.students) ? next.students.map((row) => ({ ...row })) : [])
      } catch (err: unknown) {
        setError(err instanceof ApiHttpError ? err.message : 'Save failed.')
      } finally {
        setSaving(false)
      }
      return
    }
    if (!isGradingScoreType(scoreType) || !studentId || !classSectionId || !semester || !schoolYear) return
    setSaving(true)
    setError(null)
    try {
      let body: Record<string, unknown> = {
        type: scoreType,
        student_id: Number(studentId),
        class_section_id: Number(classSectionId),
        semester,
        school_year: schoolYear,
      }
      if (['homework', 'quiz', 'project'].includes(scoreType)) {
        body = {
          ...body,
          score_ids: scoreRows.map((r) => r.id),
          scores: scoreRows.map((r) => r.score),
          comments: scoreRows.map((r) => r.comment ?? ''),
        }
      } else if (['midterm', 'final', 'test'].includes(scoreType)) {
        body = { ...body, score: singleScore === '' ? null : Number(singleScore) }
        } else if (scoreType === 'comments') {
        body = { ...body, comment: generalComment }
      }
      await postGradingScoreUpdate(body)
      const next = await fetchGradingScoreForm(
        scoreType,
        classSectionId,
        studentId,
        new URLSearchParams({
          semester,
          school_year: schoolYear,
        }),
      )
      setData(next)
      setScoreRows(Array.isArray(next.scores) ? [...next.scores] : [])
      const first = next.scores?.[0]
      setSingleScore(first?.score !== undefined && first?.score !== null ? String(first.score) : '')
      setGeneralComment(first?.comment != null ? String(first.comment) : '')
    } catch (err: unknown) {
      setError(err instanceof ApiHttpError ? err.message : 'Save failed.')
    } finally {
      setSaving(false)
    }
  }

  if (!isGradingScoreType(scoreType)) {
    return (
      <div className="container mt-4">
        <div className="alert alert-warning">Unknown score type.</div>
      </div>
    )
  }

  if ((!isSectionMode && (!studentId || !classSectionId || !semester || !schoolYear)) || (isSectionMode && !classSectionId)) {
    return (
      <div className="container mt-4">
        <div className="alert alert-info">
          Open this page from Grading Management so the route includes the section and the URL includes
          <code>semester</code> and <code>school_year</code>.
        </div>
        <Link className="btn btn-secondary" to={GRADING_PATH}>
          Return to Grading Management
        </Link>
      </div>
    )
  }

  return (
    <div className="container mt-5">
      <h2 className="text-center mb-4">
        {isSectionMode ? `Update ${title} Scores` : `${title} Scores for `}
        {!isSectionMode ? <span className="text-decoration-none">{name}</span> : null}
      </h2>
      <p className="text-center text-muted small">
        {isSectionMode ? null : <>School ID {studentSchoolId || '—'} • </>}
        {(resolvedSectionName || `Section ${classSectionId}`)} • {resolvedSemester || '—'} • {resolvedSchoolYear || '—'}
      </p>
      {(isSectionMode ? sectionLocked : locked) ? (
        <div className="alert alert-warning text-center">
          Scores are locked for this class. Unlock to edit.
        </div>
      ) : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? <p className="text-muted">Loading…</p> : null}

      {!loading && data ? (
        <form onSubmit={(e) => void onSubmit(e)}>
          {['homework', 'quiz', 'project'].includes(scoreType) ? (
            <table className="table table-bordered">
              <thead>
                <tr>
                  <th>#</th>
                  <th>Score</th>
                  <th>Comment</th>
                </tr>
              </thead>
              <tbody>
                {scoreRows.map((row, index) => (
                  <tr key={row.id ?? index}>
                    <td>{index + 1}</td>
                    <td>
                      <input
                        type="number"
                        className="form-control"
                        disabled={locked}
                        value={row.score ?? ''}
                        onChange={(ev) => {
                          const next = [...scoreRows]
                          next[index] = { ...next[index], score: ev.target.value }
                          setScoreRows(next)
                        }}
                      />
                    </td>
                    <td>
                      <textarea
                        className="form-control"
                        disabled={locked}
                        value={row.comment ?? ''}
                        onChange={(ev) => {
                          const next = [...scoreRows]
                          next[index] = { ...next[index], comment: ev.target.value }
                          setScoreRows(next)
                        }}
                      />
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          ) : null}

          {['midterm', 'final', 'test'].includes(scoreType) ? (
            <div className="mb-3">
              <label className="form-label">Score</label>
              <input
                type="number"
                className="form-control"
                disabled={locked}
                value={singleScore}
                onChange={(e) => setSingleScore(e.target.value)}
              />
            </div>
          ) : null}

          {scoreType === 'comments' ? (
            <div className="mb-3">
              <label className="form-label">General Comment</label>
              <textarea
                className="form-control"
                rows={5}
                disabled={locked}
                value={generalComment}
                onChange={(e) => setGeneralComment(e.target.value)}
              />
            </div>
          ) : null}

          <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 && isSectionMode && sectionData ? (
        <form onSubmit={(e) => void onSubmit(e)}>
          <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>
                  {['homework', 'quiz', 'project'].includes(scoreType)
                    ? sectionHeaders.map((header) => <th key={header} className="text-center">{title.replace(' Scores', '')} {header}</th>)
                    : null}
                  {['midterm', 'final'].includes(scoreType) ? <th className="text-center">Score</th> : null}
                  {scoreType === 'comments' ? (
                    <>
                      <th>PTAP Comment</th>
                      <th>PTAP Review</th>
                      {semester === 'Fall' ? <th>Midterm Comment</th> : <th>Final Comment</th>}
                      {semester === 'Fall' ? <th>Midterm Review</th> : <th>Final Review</th>}
                      <th>Attendance Comment</th>
                    </>
                  ) : null}
                </tr>
              </thead>
              <tbody>
                {visibleSectionRows.map((row, index) => (
                  <tr key={row.student_id}>
                    <td>{index + 1}</td>
                    <td>{row.school_id ?? '—'}</td>
                    <td>{row.firstname ?? '—'}</td>
                    <td>{row.lastname ?? '—'}</td>
                    {['homework', 'quiz', 'project'].includes(scoreType)
                      ? sectionHeaders.map((header) => (
                          <td key={`${row.student_id}-${header}`}>
                            <input
                              type="number"
                              min="0"
                              max="100"
                              step="0.01"
                              className="form-control text-center"
                              disabled={sectionLocked}
                              value={row.scores?.[String(header)] ?? ''}
                              onChange={(event) => updateSectionScore(row.student_id, String(header), event.target.value)}
                            />
                          </td>
                        ))
                      : null}
                    {['midterm', 'final'].includes(scoreType) ? (
                      <td>
                        <input
                          type="number"
                          min="0"
                          max="100"
                          step="0.01"
                          className="form-control text-center"
                          disabled={sectionLocked}
                          value={row.score ?? ''}
                          onChange={(event) => updateSectionExamScore(row.student_id, event.target.value)}
                        />
                      </td>
                    ) : null}
                    {scoreType === 'comments' ? (
                      <>
                        <td>
                          <textarea
                            className="form-control"
                            rows={3}
                            disabled={sectionLocked}
                            value={row.comments?.ptap?.comment ?? ''}
                            onChange={(event) => updateSectionComment(row.student_id, 'ptap', 'comment', event.target.value)}
                          />
                        </td>
                        <td>
                          <textarea
                            className="form-control"
                            rows={3}
                            disabled={sectionLocked}
                            value={row.comments?.ptap?.comment_review ?? ''}
                            onChange={(event) => updateSectionComment(row.student_id, 'ptap', 'comment_review', event.target.value)}
                          />
                        </td>
                        <td>
                          <textarea
                            className="form-control"
                            rows={3}
                            disabled={sectionLocked}
                            value={row.comments?.[semester === 'Fall' ? 'midterm' : 'final']?.comment ?? ''}
                            onChange={(event) =>
                              updateSectionComment(row.student_id, semester === 'Fall' ? 'midterm' : 'final', 'comment', event.target.value)
                            }
                          />
                        </td>
                        <td>
                          <textarea
                            className="form-control"
                            rows={3}
                            disabled={sectionLocked}
                            value={row.comments?.[semester === 'Fall' ? 'midterm' : 'final']?.comment_review ?? ''}
                            onChange={(event) =>
                              updateSectionComment(row.student_id, semester === 'Fall' ? 'midterm' : 'final', 'comment_review', event.target.value)
                            }
                          />
                        </td>
                        <td>
                          <textarea
                            className="form-control"
                            rows={3}
                            disabled={sectionLocked}
                            value={row.comments?.attendance?.comment ?? ''}
                            onChange={(event) => updateSectionComment(row.student_id, 'attendance', 'comment', event.target.value)}
                          />
                        </td>
                      </>
                    ) : null}
                  </tr>
                ))}
                {visibleSectionRows.length === 0 ? (
                  <tr>
                    <td
                      colSpan={
                        4 +
                        (['homework', 'quiz', 'project'].includes(scoreType) ? sectionHeaders.length : 0) +
                        (['midterm', 'final'].includes(scoreType) ? 1 : 0) +
                        (scoreType === 'comments' ? 5 : 0)
                      }
                      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={sectionLocked || saving}>
              {saving ? 'Saving…' : 'Save Changes'}
            </button>
          </div>
        </form>
      ) : null}

      <div className="text-center mt-4">
        <Link className="btn btn-secondary" to={GRADING_PATH}>
          Return to Main Page
        </Link>
      </div>
    </div>
  )
}
