import { useEffect, useMemo, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import {
  fetchConfigurationByKey,
  fetchGradingOverview,
  lockAllGradingScores,
  refreshGradingScores,
  toggleGradingLock,
  updateConfigurationValue,
} from '../../api/session'
import type { GradingOverviewStudentRow } from '../../api/types'
import {
  GRADING_BELOW_SIXTY_PATH,
  GRADING_DECISIONS_PATH,
  GRADING_HOMEWORK_TRACKING_PATH,
  GRADING_PARTICIPATION_PATH,
  GRADING_PLACEMENT_INDEX_PATH,
} from './gradingPaths'

const SCORE_ACTIONS = [
  { key: 'homework', label: 'Homework' },
  { key: 'quiz', label: 'Quiz' },
  { key: 'project', label: 'Project' },
  { key: 'comments', label: 'Comments' },
] as const

function normalizeQuery(value: string) {
  return value.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim()
}

export function GradingMainPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const semesterParam = searchParams.get('semester') ?? ''
  const schoolYearParam = searchParams.get('school_year') ?? ''
  const [data, setData] = useState<Awaited<ReturnType<typeof fetchGradingOverview>> | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [activeGradeKey, setActiveGradeKey] = useState<string>('')
  const [activeSectionId, setActiveSectionId] = useState<string>('')
  const [studentSearch, setStudentSearch] = useState('')
  const [tableSearch, setTableSearch] = useState('')
  const [actionBusy, setActionBusy] = useState<string | null>(null)
  const [filters, setFilters] = useState({
    school_year: schoolYearParam,
    semester: semesterParam,
  })

  async function loadOverview() {
    const result = await fetchGradingOverview({
      semester: semesterParam || null,
      schoolYear: schoolYearParam || null,
    })
    setData(result)
    const firstGradeKey = String(result.requested_class_id ?? Object.keys(result.grades ?? {})[0] ?? '')
    setActiveGradeKey(firstGradeKey)
    const firstSection = (result.grades?.[firstGradeKey] ?? [])[0]
    setActiveSectionId(String(firstSection?.class_section_id ?? ''))
  }

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const result = await fetchGradingOverview({
          semester: semesterParam || null,
          schoolYear: schoolYearParam || null,
        })
        if (cancelled) return
        setData(result)
        const firstGradeKey = String(result.requested_class_id ?? Object.keys(result.grades ?? {})[0] ?? '')
        setActiveGradeKey(firstGradeKey)
        const firstSection = (result.grades?.[firstGradeKey] ?? [])[0]
        setActiveSectionId(String(firstSection?.class_section_id ?? ''))
        if (schoolYearParam === '' || semesterParam === '') {
          const next = new URLSearchParams(searchParams)
          if (schoolYearParam === '' && (result.school_year ?? '').trim() !== '') {
            next.set('school_year', String(result.school_year))
          }
          if (semesterParam === '' && (result.semester ?? '').trim() !== '') {
            next.set('semester', String(result.semester))
          }
          setFilters({
            school_year: String(next.get('school_year') ?? result.school_year ?? ''),
            semester: String(next.get('semester') ?? result.semester ?? ''),
          })
          setSearchParams(next, { replace: true })
        }
        setError(null)
      } catch (e) {
        if (!cancelled) setError(e instanceof Error ? e.message : 'Unable to load grading hub.')
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [schoolYearParam, searchParams, semesterParam, setSearchParams])

  useEffect(() => {
    setFilters({
      school_year: schoolYearParam,
      semester: semesterParam,
    })
  }, [schoolYearParam, semesterParam])

  const grades = data?.grades ?? {}
  const studentsBySection = data?.students_by_section ?? {}
  const gradeKeys = Object.keys(grades)
  const activeGrade = activeGradeKey && grades[activeGradeKey] ? activeGradeKey : gradeKeys[0] ?? ''
  const gradeSections = grades[activeGrade] ?? []
  const displayedSection =
    gradeSections.find((section) => String(section.class_section_id) === activeSectionId) ??
    gradeSections[0] ??
    null

  useEffect(() => {
    if (!displayedSection && gradeSections[0]) {
      setActiveSectionId(String(gradeSections[0].class_section_id))
    }
  }, [displayedSection, gradeSections])

  const normalizedSearch = normalizeQuery(studentSearch)
  const sectionQuery = normalizeQuery(tableSearch)
  const searchMatches = useMemo(() => {
    if (normalizedSearch === '') return [] as Array<{
      sectionId: string
      sectionName: string
      classId: string
      student: GradingOverviewStudentRow
    }>

    const matches: Array<{
      sectionId: string
      sectionName: string
      classId: string
      student: GradingOverviewStudentRow
    }> = []

    for (const [classId, sections] of Object.entries(grades)) {
      for (const section of sections ?? []) {
        const sectionId = String(section.class_section_id ?? '')
        const sectionName = section.class_section_name ?? `Section ${sectionId}`
        const rows = studentsBySection[sectionId] ?? []
        for (const student of rows) {
          const haystack = normalizeQuery(`${student.school_id ?? ''} ${student.firstname ?? ''} ${student.lastname ?? ''} ${sectionName}`)
          if (haystack.includes(normalizedSearch)) {
            matches.push({ sectionId, sectionName, classId, student })
          }
        }
      }
    }
    return matches
  }, [grades, normalizedSearch, studentsBySection])

  const renderedRows = useMemo(() => {
    if (normalizedSearch !== '') return searchMatches
    if (!displayedSection) return [] as Array<{
      sectionId: string
      sectionName: string
      classId: string
      student: GradingOverviewStudentRow
    }>

    const sectionId = String(displayedSection.class_section_id ?? '')
    const sectionName = displayedSection.class_section_name ?? `Section ${sectionId}`
    return (studentsBySection[sectionId] ?? []).map((student) => ({
      sectionId,
      sectionName,
      classId: activeGrade,
      student,
    }))
  }, [activeGrade, displayedSection, normalizedSearch, searchMatches, studentsBySection])

  const visibleRows = useMemo(() => {
    if (sectionQuery === '') return renderedRows
    return renderedRows.filter(({ sectionName, student }) => {
      const haystack = normalizeQuery(`${student.school_id ?? ''} ${student.firstname ?? ''} ${student.lastname ?? ''} ${sectionName}`)
      return haystack.includes(sectionQuery)
    })
  }, [renderedRows, sectionQuery])

  const gradeCount = (classId: string) =>
    (grades[classId] ?? []).reduce((count, section) => count + (studentsBySection[String(section.class_section_id)]?.length ?? 0), 0)

  const gradeLabel = (classId: string) => {
    const numeric = Number(classId)
    if (numeric === 13) return 'KG'
    if (numeric === 12) return 'Youth'
    return `Grade ${classId}`
  }

  const q = searchParams.toString()
  const qs = q ? `?${q}` : ''
  const selectedSectionId = Number(displayedSection?.class_section_id ?? 0)
  const selectedSemester = data?.semester ?? semesterParam
  const selectedSchoolYear = data?.school_year ?? schoolYearParam
  const selectedLocked = selectedSectionId > 0 ? Boolean(data?.score_locks?.[String(selectedSectionId)]) : false
  const normalizedSemester = selectedSemester.trim().toLowerCase()

  async function handleToggleSectionLock() {
    if (!selectedSectionId || !selectedSemester || !selectedSchoolYear) return
    setActionBusy('toggle-lock')
    try {
      await toggleGradingLock({
        class_section_id: selectedSectionId,
        semester: selectedSemester,
        school_year: selectedSchoolYear,
      })
      await loadOverview()
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to update score lock.')
    } finally {
      setActionBusy(null)
    }
  }

  async function handleRefreshScores() {
    if (!selectedSectionId || !selectedSemester || !selectedSchoolYear) return
    setActionBusy('refresh')
    try {
      await refreshGradingScores({
        class_section_id: selectedSectionId,
        semester: selectedSemester,
        school_year: selectedSchoolYear,
      })
      await loadOverview()
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to refresh scores.')
    } finally {
      setActionBusy(null)
    }
  }

  async function handleLockAllScores() {
    if (!selectedSemester || !selectedSchoolYear) return
    setActionBusy('lock-all')
    try {
      await lockAllGradingScores({
        semester: selectedSemester,
        school_year: selectedSchoolYear,
      })
      await loadOverview()
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to lock all scores.')
    } finally {
      setActionBusy(null)
    }
  }

  async function handleToggleParentRelease(semester: 'Fall' | 'Spring') {
    const key = semester === 'Fall' ? 'parent_scores_released_fall' : 'parent_scores_released_spring'
    const current = semester === 'Fall' ? Boolean(data?.scores_released_fall) : Boolean(data?.scores_released_spring)
    setActionBusy(`release-${semester.toLowerCase()}`)
    try {
      const configResponse = await fetchConfigurationByKey(key)
      const configId = Number(configResponse.config?.id ?? 0)
      if (!configId) {
        throw new Error(`Configuration ${key} was not found.`)
      }
      await updateConfigurationValue(configId, {
        config_key: key,
        config_value: current ? '0' : '1',
      })
      await loadOverview()
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to update parent score release.')
    } finally {
      setActionBusy(null)
    }
  }

  return (
    <div className="container-fluid py-3">
      <div className="text-center mt-2 mb-3">
        <h2 className="display-6 mb-2">Grading Management</h2>
      </div>

      <form
        className="row g-2 justify-content-center align-items-end mb-3"
        onSubmit={(event) => {
          event.preventDefault()
          const next = new URLSearchParams()
          if (filters.school_year.trim() !== '') next.set('school_year', filters.school_year.trim())
          if (filters.semester.trim() !== '') next.set('semester', filters.semester.trim())
          setSearchParams(next)
        }}
      >
        <div className="col-12 col-md-auto">
          <label className="form-label">School year</label>
          <input
            className="form-control"
            value={filters.school_year}
            onChange={(event) => setFilters((current) => ({ ...current, school_year: event.target.value }))}
            placeholder={data?.school_year ?? '2025-2026'}
          />
        </div>
        <div className="col-12 col-md-auto">
          <label className="form-label">Semester</label>
          <select
            className="form-select"
            value={filters.semester}
            onChange={(event) => setFilters((current) => ({ ...current, semester: event.target.value }))}
          >
            {(data?.semester_options ?? ['Fall', 'Spring']).map((option) => (
              <option key={option} value={option}>{option}</option>
            ))}
          </select>
        </div>
        <div className="col-12 col-md-auto d-flex gap-2">
          <button className="btn btn-primary" type="submit">Apply</button>
          <button
            className="btn btn-outline-secondary"
            type="button"
            onClick={() => {
              setFilters({ school_year: '', semester: '' })
              setSearchParams(new URLSearchParams())
            }}
          >
            Reset
          </button>
        </div>
      </form>

      <div className="row g-2 justify-content-center mb-3">
        <div className="col-12 col-md-8 col-lg-6">
          <div className="input-group">
            <span className="input-group-text">Search Student</span>
            <input
              className="form-control"
              type="text"
              placeholder="Type School ID or Student Name"
              value={studentSearch}
              onChange={(event) => setStudentSearch(event.target.value)}
            />
            <button className="btn btn-outline-secondary" type="button" onClick={() => setStudentSearch('')}>
              Clear
            </button>
          </div>
          <small className="text-muted">Searches all grades.</small>
        </div>
      </div>

      <div className="row justify-content-center mb-3">
        <div className="col-auto d-flex flex-wrap gap-2 justify-content-center">
          <Link className="btn btn-outline-primary" to={`${GRADING_DECISIONS_PATH}${qs}`}>Decisions</Link>
          <Link className="btn btn-outline-primary" to={`${GRADING_BELOW_SIXTY_PATH}${qs}`}>Below 60 Summary</Link>
          <Link className="btn btn-outline-primary" to={`${GRADING_HOMEWORK_TRACKING_PATH}${qs}`}>Homework Tracking</Link>
          <Link className="btn btn-outline-primary" to={`${GRADING_PLACEMENT_INDEX_PATH}${qs}`}>Placement Scores</Link>
        </div>
      </div>

      <div className="row justify-content-center mb-3">
        <div className="col-auto d-flex flex-wrap gap-2 justify-content-center">
          <button
            className={`btn ${data?.scores_released_fall ? 'btn-outline-danger' : 'btn-outline-success'}`}
            type="button"
            disabled={actionBusy !== null}
            onClick={() => void handleToggleParentRelease('Fall')}
          >
            {actionBusy === 'release-fall'
              ? 'Updating…'
              : `Release scores for Parent - Fall: ${data?.scores_released_fall ? 'ON' : 'OFF'}`}
          </button>
          <button
            className={`btn ${data?.scores_released_spring ? 'btn-outline-danger' : 'btn-outline-success'}`}
            type="button"
            disabled={actionBusy !== null}
            onClick={() => void handleToggleParentRelease('Spring')}
          >
            {actionBusy === 'release-spring'
              ? 'Updating…'
              : `Release scores for Parent - Spring: ${data?.scores_released_spring ? 'ON' : 'OFF'}`}
          </button>
          <button
            className="btn btn-outline-danger"
            type="button"
            disabled={!selectedSemester || !selectedSchoolYear || actionBusy !== null}
            onClick={() => void handleLockAllScores()}
          >
            {actionBusy === 'lock-all' ? 'Locking…' : 'Lock All Scores'}
          </button>
        </div>
      </div>

      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? (
        <p className="text-muted">Loading grading overview…</p>
      ) : gradeKeys.length === 0 ? (
        <p className="text-muted">No grading sections found.</p>
      ) : (
        <>
          <ul className="nav nav-tabs flex-wrap justify-content-center mb-4 border-bottom">
            {gradeKeys.map((classId) => (
              <li key={classId} className="nav-item">
                <button
                  type="button"
                  className={`nav-link d-flex align-items-center gap-2 ${classId === activeGrade ? 'active' : ''}`}
                  onClick={() => setActiveGradeKey(classId)}
                  style={{ color: classId === activeGrade ? '#1f2937' : '#334155' }}
                >
                  <span
                    aria-hidden="true"
                    style={{
                      width: 10,
                      height: 10,
                      borderRadius: '50%',
                      backgroundColor: (grades[classId] ?? []).every((section) => Boolean(data?.score_locks?.[String(section.class_section_id)]))
                        ? '#198754'
                        : '#dc3545',
                      display: 'inline-block',
                    }}
                  />
                  <span>{gradeLabel(classId)}</span>
                  <span className="badge rounded-pill text-bg-secondary">{gradeCount(classId)}</span>
                </button>
              </li>
            ))}
          </ul>

          <div className="d-flex flex-wrap justify-content-center gap-2 mb-3">
            {gradeSections.map((section) => (
              <button
                key={section.class_section_id}
                type="button"
                className={`btn btn-sm ${String(section.class_section_id) === String(displayedSection?.class_section_id ?? '') ? 'btn-primary' : 'btn-outline-primary'}`}
                onClick={() => setActiveSectionId(String(section.class_section_id))}
              >
                {section.class_section_name}
              </button>
            ))}
          </div>

          {normalizedSearch !== '' && searchMatches.length > 0 ? (
            <div className="row g-2 justify-content-center mb-3">
              <div className="col-12 col-md-8 col-lg-6">
                <div className="list-group" style={{ maxHeight: 240, overflowY: 'auto' }}>
                  {searchMatches.slice(0, 12).map((match) => (
                    <button
                      key={`${match.sectionId}-${match.student.id}`}
                      type="button"
                      className="list-group-item list-group-item-action"
                      onClick={() => {
                        setActiveGradeKey(match.classId)
                        setActiveSectionId(match.sectionId)
                      }}
                    >
                      <div className="fw-semibold">{match.student.school_id ?? '—'} - {`${match.student.firstname ?? ''} ${match.student.lastname ?? ''}`.trim()}</div>
                      <div className="small text-muted">{match.sectionName}</div>
                    </button>
                  ))}
                </div>
              </div>
            </div>
          ) : null}

          {displayedSection || normalizedSearch !== '' ? (
            <>
              <div className="text-center mb-3">
                <h3 className="h2 mb-2">{normalizedSearch !== '' ? 'Search Results' : (displayedSection?.class_section_name ?? 'Scores')}</h3>
                <div className="text-muted small">
                  {data?.semester || '—'} {data?.school_year ? `• ${data.school_year}` : ''}
                </div>
              </div>

              <div className="d-flex flex-wrap justify-content-center gap-2 mb-3">
                <button
                  className="btn btn-sm btn-outline-danger"
                  type="button"
                  disabled={!selectedSectionId || !selectedSemester || !selectedSchoolYear || actionBusy !== null}
                  onClick={() => void handleToggleSectionLock()}
                >
                  {actionBusy === 'toggle-lock' ? 'Updating…' : selectedLocked ? 'Unlock Scores' : 'Lock Scores'}
                </button>
                {SCORE_ACTIONS.map((action) => (
                  <Link
                    key={action.key}
                    className="btn btn-sm btn-outline-primary"
                    to={displayedSection ? `/app/grading/scores/${action.key}/${displayedSection.class_section_id}${qs}` : '#'}
                  >
                    {action.label}
                  </Link>
                ))}
                {normalizedSemester === 'fall' ? (
                  <Link
                    className="btn btn-sm btn-outline-primary"
                    to={displayedSection ? `/app/grading/scores/midterm/${displayedSection.class_section_id}${qs}` : '#'}
                  >
                    Midterm
                  </Link>
                ) : null}
                {normalizedSemester === 'spring' ? (
                  <Link
                    className="btn btn-sm btn-outline-primary"
                    to={displayedSection ? `/app/grading/scores/final/${displayedSection.class_section_id}${qs}` : '#'}
                  >
                    Final
                  </Link>
                ) : null}
                <Link
                  className="btn btn-sm btn-outline-primary"
                  to={
                    selectedSectionId
                      ? `${GRADING_PARTICIPATION_PATH}?class_section_id=${encodeURIComponent(String(selectedSectionId))}${selectedSemester ? `&semester=${encodeURIComponent(selectedSemester)}` : ''}${selectedSchoolYear ? `&school_year=${encodeURIComponent(selectedSchoolYear)}` : ''}`
                      : GRADING_PARTICIPATION_PATH
                  }
                >
                  Participation
                </Link>
                <button
                  className="btn btn-sm btn-outline-secondary"
                  type="button"
                  disabled={!selectedSectionId || !selectedSemester || !selectedSchoolYear || actionBusy !== null}
                  onClick={() => void handleRefreshScores()}
                >
                  {actionBusy === 'refresh' ? 'Recomputing…' : 'Refresh / Recalculate Scores'}
                </button>
              </div>

              <div className="d-flex flex-wrap justify-content-between align-items-center gap-3 mb-2">
                <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>School ID</th>
                      {normalizedSearch !== '' ? <th>Section</th> : null}
                      <th>Student Name</th>
                      <th>Homework</th>
                      <th>Quiz</th>
                      <th>Project</th>
                      <th>Participation</th>
                      <th>Midterm</th>
                      <th>Final</th>
                      <th>Semester Score</th>
                    </tr>
                  </thead>
                  <tbody>
                    {visibleRows.map(({ sectionId, sectionName, student }) => (
                      <tr key={`${sectionId}-${student.id}`}>
                        <td>{student.school_id ?? '—'}</td>
                        {normalizedSearch !== '' ? <td>{sectionName}</td> : null}
                        <td>{`${student.firstname ?? ''} ${student.lastname ?? ''}`.trim() || '—'}</td>
                        <td>{student.homework_avg ?? '—'}</td>
                        <td>{student.quiz_avg ?? '—'}</td>
                        <td>{student.project_avg ?? '—'}</td>
                        <td>{student.participation ?? '—'}</td>
                        <td>{student.midterm_exam ?? '—'}</td>
                        <td>{student.final_exam ?? '—'}</td>
                        <td>{student.semester_score ?? '—'}</td>
                      </tr>
                    ))}
                    {visibleRows.length === 0 ? (
                      <tr>
                        <td colSpan={normalizedSearch !== '' ? 10 : 9} className="text-muted text-center">
                          No students match the current search.
                        </td>
                      </tr>
                    ) : null}
                  </tbody>
                </table>
              </div>
            </>
          ) : null}
        </>
      )}
    </div>
  )
}
