import { type FormEvent, useEffect, useMemo, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { ApiHttpError } from '../../api/http'
import {
  fetchCertificateReprint,
  fetchCertificatesDashboard,
  postCertificateGenerate,
  type CertificateDashboardPayload,
  type CertificateSectionRow,
  type CertificateStudentRow,
} from '../../api/certificates'

function formatScore(value: number | null) {
  return value == null ? '—' : value.toFixed(2)
}

function isoToday() {
  return new Date().toISOString().slice(0, 10)
}

function toDisplayDate(isoDate: string) {
  const date = new Date(`${isoDate}T00:00:00`)
  if (Number.isNaN(date.getTime())) return isoDate
  return `${String(date.getMonth() + 1).padStart(2, '0')}/${String(date.getDate()).padStart(2, '0')}/${date.getFullYear()}`
}

function downloadBlob(blob: Blob) {
  const url = URL.createObjectURL(blob)
  window.open(url, '_blank', 'noopener')
  window.setTimeout(() => URL.revokeObjectURL(url), 60_000)
}

function DecisionBadge({ student }: { student: CertificateStudentRow }) {
  const colorMap: Record<string, string> = {
    Pass: 'success',
    'Repeat Class': 'danger',
    'Make-up exam in fall': 'info',
    'Deferred decision': 'info',
    Expel: 'danger',
    Withdrawn: 'secondary',
  }

  if (student.decision_rows.length === 0 || student.decision_state === 'pending') {
    return <span className="badge bg-warning text-dark">Pending</span>
  }

  if (student.decision_labels.length === 0) {
    return <span className="text-muted small">—</span>
  }

  return (
    <>
      {student.decision_labels.map((label) => (
        <span key={label} className={`badge bg-${colorMap[label] ?? 'secondary'} me-1`}>
          {label}
        </span>
      ))}
    </>
  )
}

function StatusDot({ hasPass, fullyDone }: { hasPass: boolean; fullyDone: boolean }) {
  const className = !hasPass ? 'no-eligible' : fullyDone ? 'done' : 'pending'
  return <span className={`cert-status-dot ${className}`} aria-hidden />
}

function CertificateSectionCard({
  section,
  schoolYear,
  defaultCertDate,
  onGenerated,
}: {
  section: CertificateSectionRow
  schoolYear: string
  defaultCertDate: string
  onGenerated: () => Promise<void> | void
}) {
  const eligibleStudents = useMemo(
    () => section.students.filter((student) => student.eligible),
    [section.students],
  )
  const [selectedIds, setSelectedIds] = useState<number[]>([])
  const [certDate, setCertDate] = useState(isoToday())
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    setSelectedIds([])
    setCertDate(isoToday())
    setError(null)
  }, [section.section_id, defaultCertDate])

  const allSelected = eligibleStudents.length > 0 && selectedIds.length === eligibleStudents.length
  const partiallySelected = selectedIds.length > 0 && !allSelected

  async function handleGenerate(event: FormEvent) {
    event.preventDefault()
    if (selectedIds.length === 0) {
      setError('Please select at least one student.')
      return
    }

    setBusy(true)
    setError(null)

    try {
      const blob = await postCertificateGenerate({
        student_ids: selectedIds,
        cert_date: toDisplayDate(certDate),
        class_section_id: section.section_id,
        school_year: schoolYear,
      })
      downloadBlob(blob)
      await onGenerated()
      setSelectedIds([])
    } catch (e) {
      setError(e instanceof ApiHttpError ? e.message : 'Failed to generate certificates.')
    } finally {
      setBusy(false)
    }
  }

  async function handleReprint(certificateNumber: string) {
    setBusy(true)
    setError(null)

    try {
      const blob = await fetchCertificateReprint(certificateNumber)
      downloadBlob(blob)
    } catch (e) {
      setError(e instanceof ApiHttpError ? e.message : 'Failed to reprint certificate.')
    } finally {
      setBusy(false)
    }
  }

  function toggleStudent(studentId: number) {
    setSelectedIds((previous) =>
      previous.includes(studentId)
        ? previous.filter((id) => id !== studentId)
        : [...previous, studentId],
    )
  }

  function toggleAll(checked: boolean) {
    setSelectedIds(checked ? eligibleStudents.map((student) => student.student_id) : [])
  }

  return (
    <form className="mb-5" onSubmit={handleGenerate}>
      <h4 className="mt-4 mb-2 text-center">{section.section_name}</h4>

      {error ? <div className="alert alert-danger py-2">{error}</div> : null}

      <div className="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-2">
        <div className="d-flex align-items-center gap-4 flex-wrap">
          <span className="fw-semibold">
            Students <span className="badge bg-secondary ms-1">{section.student_count}</span>
          </span>
          <span className="text-muted small">
            <strong className="text-success">{section.pass_count}</strong> Pass
          </span>
          <span className="text-muted small">
            <strong className="text-primary">{section.cert_count}</strong> Generated
          </span>
          <span className="text-muted small">
            <strong className={section.remaining_count > 0 ? 'text-warning' : 'text-muted'}>
              {section.remaining_count}
            </strong>{' '}
            Remaining
          </span>
        </div>

        <div className="input-group input-group-sm" style={{ width: 200 }}>
          <span className="input-group-text">
            <i className="bi bi-calendar3" />
          </span>
          <input
            type="date"
            className="form-control"
            value={certDate}
            onChange={(event) => setCertDate(event.target.value)}
            title="Certificate date"
          />
        </div>
      </div>

      <div className="table-responsive">
        <table className="table table-hover table-striped align-middle mb-0">
          <thead className="table-light">
            <tr>
              <th style={{ width: 40 }} className="text-center">
                <input
                  className="form-check-input"
                  type="checkbox"
                  checked={allSelected}
                  ref={(node) => {
                    if (node) node.indeterminate = partiallySelected
                  }}
                  onChange={(event) => toggleAll(event.target.checked)}
                />
              </th>
              <th>First Name</th>
              <th>Last Name</th>
              <th className="text-center">Year Score</th>
              <th>Decision</th>
              <th>Certificate No.</th>
            </tr>
          </thead>
          <tbody>
            {section.students.map((student) => (
              <tr key={student.student_id}>
                <td className="text-center">
                  <input
                    className="form-check-input"
                    type="checkbox"
                    checked={selectedIds.includes(student.student_id)}
                    disabled={!student.eligible || busy}
                    onChange={() => toggleStudent(student.student_id)}
                  />
                </td>
                <td>{student.firstname}</td>
                <td>{student.lastname}</td>
                <td className="text-center fw-semibold">{formatScore(student.year_score)}</td>
                <td>
                  <DecisionBadge student={student} />
                </td>
                <td>
                  {student.certificate_number ? (
                    <button
                      type="button"
                      className="btn btn-link btn-sm p-0 font-monospace"
                      disabled={busy}
                      onClick={() => handleReprint(student.certificate_number as string)}
                    >
                      {student.certificate_number}
                    </button>
                  ) : (
                    <span className="text-muted">—</span>
                  )}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      <div className="d-flex justify-content-between align-items-center mt-2">
        <span className="text-muted small">
          {selectedIds.length} student{selectedIds.length !== 1 ? 's' : ''} selected
        </span>
        <button type="submit" className="btn btn-success" disabled={selectedIds.length === 0 || busy}>
          {busy ? (
            <>
              <span className="spinner-border spinner-border-sm me-1" />
              Generating...
            </>
          ) : (
            <>
              <i className="bi bi-printer me-1" />
              Generate & Print Certificates
            </>
          )}
        </button>
      </div>
    </form>
  )
}

export function CertificatesPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const schoolYear = searchParams.get('school_year') ?? ''
  const groupKey = searchParams.get('group') ?? ''

  const [data, setData] = useState<CertificateDashboardPayload | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [yearInput, setYearInput] = useState('')

  async function loadDashboard(currentSchoolYear: string) {
    setLoading(true)
    setError(null)

    try {
      const payload = await fetchCertificatesDashboard({
        school_year: currentSchoolYear || undefined,
      })
      setData(payload)
      setYearInput(payload.school_year || currentSchoolYear)
    } catch (e) {
      setError(e instanceof ApiHttpError ? e.message : 'Failed to load certificate dashboard.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void loadDashboard(schoolYear)
  }, [schoolYear])

  const groups = data?.grade_groups ?? []
  const activeGroupKey =
    (groupKey && groups.some((group) => group.key === groupKey) ? groupKey : '') ||
    data?.default_group_key ||
    groups[0]?.key ||
    ''
  const activeGroup = groups.find((group) => group.key === activeGroupKey) ?? null

  function applySchoolYear(event: FormEvent) {
    event.preventDefault()
    const next = new URLSearchParams(searchParams)
    if (yearInput.trim()) next.set('school_year', yearInput.trim())
    else next.delete('school_year')
    next.delete('group')
    setSearchParams(next, { replace: true })
  }

  function setActiveGroup(nextGroupKey: string) {
    const next = new URLSearchParams(searchParams)
    next.set('group', nextGroupKey)
    if (schoolYear) next.set('school_year', schoolYear)
    setSearchParams(next, { replace: true })
  }

  return (
    <div className="container-fluid">
      <div className="wrapper">
        <div className="d-flex justify-content-between align-items-center flex-wrap gap-2 mt-4 mb-3">
          <div>
            <h2 className="mb-1">
              <i className="bi bi-award me-2" />
              Generate Certificates
            </h2>
            <div className="text-muted small">
              Students are eligible only when the saved final generated decision is Pass.
            </div>
          </div>
          <Link className="btn btn-outline-secondary btn-sm" to="/app/administrator/certificates/log">
            <i className="bi bi-journal-check me-1" />
            Audit Log
          </Link>
        </div>

        {error ? <div className="alert alert-danger">{error}</div> : null}

        <div className="d-flex justify-content-end mb-3">
          <form className="d-flex gap-2 align-items-center" onSubmit={applySchoolYear}>
            <label className="form-label mb-0 me-1 text-muted small">School Year</label>
            <input
              type="text"
              className="form-control form-control-sm"
              style={{ width: 130 }}
              value={yearInput}
              onChange={(event) => setYearInput(event.target.value)}
              placeholder="e.g. 2024-2025"
            />
            <button type="submit" className="btn btn-sm btn-outline-primary">
              <i className="bi bi-arrow-repeat me-1" />
              Reload
            </button>
          </form>
        </div>

        {loading ? <div className="text-muted">Loading certificates…</div> : null}

        {!loading && groups.length === 0 ? (
          <div className="alert alert-info">No classes found for {data?.school_year || schoolYear || 'this year'}.</div>
        ) : null}

        {!loading && groups.length > 0 ? (
          <>
            <ul className="nav nav-tabs justify-content-center" style={{ flexWrap: 'wrap', rowGap: '.25rem' }}>
              {groups.map((group) => (
                <li className="nav-item" key={group.key}>
                  <button
                    type="button"
                    className={`nav-link ${group.key === activeGroupKey ? 'active' : ''}`}
                    onClick={() => setActiveGroup(group.key)}
                  >
                    <StatusDot hasPass={group.has_pass} fullyDone={group.fully_done} />
                    {group.label}
                    <span className="badge bg-secondary ms-1">{group.total}</span>
                  </button>
                </li>
              ))}
            </ul>

            <div className="mt-3">
              {activeGroup?.sections.map((section) => (
                <CertificateSectionCard
                  key={section.section_id}
                  section={section}
                  schoolYear={data?.school_year ?? schoolYear}
                  defaultCertDate={data?.cert_date ?? ''}
                  onGenerated={() => loadDashboard(data?.school_year ?? schoolYear)}
                />
              ))}
            </div>
          </>
        ) : null}
      </div>

      <style>{`
        .cert-status-dot {
          display: inline-block;
          width: 8px;
          height: 8px;
          border-radius: 50%;
          margin-right: 5px;
          vertical-align: middle;
          flex-shrink: 0;
        }
        .cert-status-dot.done { background-color: #198754; }
        .cert-status-dot.pending { background-color: #dc3545; }
        .cert-status-dot.no-eligible { background-color: #adb5bd; }
      `}</style>
    </div>
  )
}
