import { type FormEvent, useEffect, useMemo, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { apiUrl } from '../../lib/apiOrigin'
import { useSchoolYearOptions } from '../../hooks/useSchoolYearOptions'
import {
  fetchStaffMonthlyAttendanceOverview,
  saveStaffMonthlyAttendanceCell,
} from '../../api/session'
import type {
  StaffMonthlyAdminRow,
  StaffMonthlyOverviewPayload,
  StaffMonthlySection,
  StaffMonthlyTeacherRow,
} from '../../api/types'
import './TeacherAttendanceMonthPage.css'
import { TEACHER_ATTENDANCE_MONTH_PATH } from './attendancePaths'

function inferSemesterByDate(dateStr: string, schoolYear: string): string {
  try {
    if (!schoolYear.includes('-')) return ''
    const parts = schoolYear.split('-')
    const y1 = parseInt(parts[0]!, 10)
    const y2 = parseInt(parts[1]!, 10)
    if (!y1 || !y2) return ''
    const fallStart = new Date(`${y1}-09-21T00:00:00Z`)
    const fallEnd = new Date(`${y2}-01-18T00:00:00Z`)
    const spStart = new Date(`${y2}-01-25T00:00:00Z`)
    const spEnd = new Date(`${y2}-05-30T00:00:00Z`)
    const d = new Date(`${dateStr}T00:00:00Z`)
    if (d >= fallStart && d <= fallEnd) return 'Fall'
    if (d >= spStart && d <= spEnd) return 'Spring'
    const m = d.getUTCMonth() + 1
    return m >= 9 || m <= 1 ? 'Fall' : 'Spring'
  } catch {
    return ''
  }
}

function selectClass(
  value: string,
): 'att-select form-select form-select-sm att-none' | 'att-select form-select form-select-sm att-present' | 'att-select form-select form-select-sm att-absent' | 'att-select form-select form-select-sm att-late' {
  const v = value.toLowerCase()
  if (v === 'present') return 'att-select form-select form-select-sm att-present'
  if (v === 'absent') return 'att-select form-select form-select-sm att-absent'
  if (v === 'late') return 'att-select form-select form-select-sm att-late'
  return 'att-select form-select form-select-sm att-none'
}

/** Port of `Views/attendance/teacher_attendance_month.php` — interactive monthly grids (JWT; no CI CSRF). */
export function TeacherAttendanceMonthPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const semesterParam = searchParams.get('semester') ?? '---'
  const schoolYearParam = searchParams.get('school_year') ?? ''

  const [payload, setPayload] = useState<StaffMonthlyOverviewPayload | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [toast, setToast] = useState<{ ok: boolean; text: string } | null>(null)

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      setError(null)
      try {
        const data = await fetchStaffMonthlyAttendanceOverview({
          semester: semesterParam === '---' ? null : semesterParam,
          schoolYear: schoolYearParam || null,
        })
        if (!cancelled) {
          setPayload(data)
          if (!schoolYearParam && data.filters?.school_year) {
            const next = new URLSearchParams(searchParams)
            next.set('school_year', data.filters.school_year)
            if (!next.get('semester')) next.set('semester', semesterParam)
            setSearchParams(next, { replace: true })
          }
        }
      } catch (e) {
        if (!cancelled) setError(e instanceof Error ? e.message : 'Unable to load monthly attendance.')
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [semesterParam, schoolYearParam])

  const filters = payload?.filters ?? {}
  const sundays = payload?.sundays ?? []
  const noSchoolSet = useMemo(
    () => new Set(payload?.noSchoolDays ?? payload?.no_school_days ?? []),
    [payload?.noSchoolDays, payload?.no_school_days],
  )
  const isCurrentYear = payload?.isCurrentYear !== false
  const schoolYears = useMemo(() => {
    const raw = payload?.schoolYears ?? []
    const ys: string[] = []
    for (const y of raw) {
      if (typeof y === 'string') ys.push(y)
      else if (y && typeof y === 'object' && 'school_year' in y && y.school_year)
        ys.push(String(y.school_year))
    }
    if (ys.length === 0 && schoolYearParam) ys.push(schoolYearParam)
    return ys
  }, [payload?.schoolYears, schoolYearParam])
  const { options } = useSchoolYearOptions({
    legacyYears: schoolYears,
    preferredYear: schoolYearParam,
  })

  const hasTeacherSections = (payload?.sections?.length ?? 0) > 0
  const hasAdmins = (payload?.admins?.length ?? 0) > 0

  async function onCellChange(
    kind: 'teacher' | 'admin',
    patch: {
      userId: string
      date: string
      status: string
      roleName: string
      sectionCode?: string | null
    },
  ) {
    if (!isCurrentYear) {
      setToast({ ok: false, text: 'Editing disabled for non-current year' })
      return
    }
    let semesterForSave = filters.semester ?? semesterParam
    if (semesterForSave === '---') {
      semesterForSave = inferSemesterByDate(patch.date, filters.school_year ?? schoolYearParam)
    }
    const body: Record<string, string> = {
      date: patch.date,
      status: patch.status,
      user_id: patch.userId,
      semester: semesterForSave,
      school_year: filters.school_year ?? schoolYearParam,
      role_name: patch.roleName,
      type: kind,
    }
    if (patch.sectionCode) body.section_id = patch.sectionCode

    try {
      await saveStaffMonthlyAttendanceCell(body)
      setToast({ ok: true, text: 'Saved' })
      const data = await fetchStaffMonthlyAttendanceOverview({
        semester: semesterParam === '---' ? null : semesterParam,
        schoolYear: schoolYearParam || null,
      })
      setPayload(data)
    } catch {
      setToast({ ok: false, text: 'Save failed' })
    }
  }

  function applyFilter(e: FormEvent<HTMLFormElement>) {
    e.preventDefault()
    const fd = new FormData(e.currentTarget)
    const p = new URLSearchParams()
    const sy = String(fd.get('school_year') ?? '')
    const sem = String(fd.get('semester') ?? '---')
    if (sy) p.set('school_year', sy)
    p.set('semester', sem)
    setSearchParams(p)
  }

  const queryString =
    filters.semester && filters.school_year
      ? `?${new URLSearchParams({
          semester: filters.semester === '---' ? '' : filters.semester,
          school_year: filters.school_year,
        }).toString()}`
      : ''

  return (
    <div className="container-fluid py-4 att-month-wrap">
      <div className="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-3">
        <h2 className="mb-0">Admin &amp; Teacher — Monthly Attendance</h2>
        <div className="legend small">
          <span className="badge bg-success">P</span>
          <span className="ms-1">Present</span>
          <span className="badge bg-danger ms-3">A</span>
          <span className="ms-1">Absent</span>
          <span className="badge bg-warning text-dark ms-3">L</span>
          <span className="ms-1">Late</span>
          <span className="badge bg-info text-dark ms-3">NS</span>
          <span className="ms-1">No School</span>
          <span className="ms-3 text-muted">—</span>
          <span className="ms-1">No entry</span>
        </div>
      </div>

      {toast ? (
        <div className={`alert alert-${toast.ok ? 'success' : 'danger'} py-2`}>{toast.text}</div>
      ) : null}

      {payload?.missingYear ? (
        <div className="alert alert-warning" role="alert">
          Current school year is not configured. This page is read-only until configured (key:{' '}
          <code>school_year</code>).
        </div>
      ) : null}

      <form className="row gy-2 gx-3 align-items-end justify-content-center mb-4" onSubmit={applyFilter}>
        <div className="col-md-3">
          <label className="form-label">School Year</label>
          <select name="school_year" className="form-select" defaultValue={schoolYearParam}>
            {options.map((option) => (
              <option key={option.value} value={option.value}>
                {option.label}
              </option>
            ))}
          </select>
        </div>
        <div className="col-md-2">
          <label className="form-label">Semester</label>
          <select name="semester" className="form-select" defaultValue={semesterParam}>
            {['---', 'Fall', 'Spring'].map((s) => (
              <option key={s} value={s}>
                {s}
              </option>
            ))}
          </select>
        </div>
        <div className="col-md-4 d-flex gap-2">
          <button type="submit" className="btn btn-secondary">
            Load
          </button>
          <Link className="btn btn-outline-secondary" to={TEACHER_ATTENDANCE_MONTH_PATH}>
            Reset
          </Link>
          <a
            className="btn btn-outline-primary"
            href={apiUrl(`/api/v1/attendance/staff/month-csv${queryString}`)}
          >
            Export CSV
          </a>
        </div>
      </form>

      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? (
        <p className="text-muted">Loading…</p>
      ) : (
        <>
          <div className="card shadow-sm mb-4">
            <div className="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
              <div>
                <strong>
                  Teachers &amp; Assistants — Sundays in{' '}
                  <span>{filters.range_label ?? filters.month_label ?? schoolYearParam}</span>
                </strong>
                {!isCurrentYear ? <span className="badge bg-secondary ms-2">Read-only (Past Year)</span> : null}
              </div>
              <small className="text-muted">Use the dropdowns to set attendance inline</small>
            </div>
            <div className="card-body month-grid-wrap">
              {!hasTeacherSections ? (
                <div className="alert alert-info mb-3">
                  No teacher assignment rows were returned for this term. Attendance entries in
                  <code className="ms-1">staff_attendance</code> only display here for users who are also assigned in
                  <code className="ms-1">teacher_class</code>.
                </div>
              ) : null}
              <TeachersGrid
                sections={payload?.sections ?? []}
                sundays={sundays}
                noSchoolSet={noSchoolSet}
                isCurrentYear={isCurrentYear}
                onCellChange={(p) => void onCellChange('teacher', p)}
              />
            </div>
          </div>

          <div className="card shadow-sm mb-4">
            <div className="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
              <div>
                <strong>
                  Admins — Sundays in{' '}
                  <span>{filters.range_label ?? filters.month_label ?? schoolYearParam}</span>
                </strong>
                <span className="text-muted ms-2">(All roles except Parent/Guest/Teacher/Teacher Assistant)</span>
              </div>
            </div>
            <div className="card-body month-grid-wrap">
              {!hasAdmins ? (
                <div className="alert alert-info mb-3">
                  No admin attendance rows were returned for this term.
                </div>
              ) : null}
              <AdminsGrid
                admins={payload?.admins ?? []}
                sundays={sundays}
                noSchoolSet={noSchoolSet}
                isCurrentYear={isCurrentYear}
                onCellChange={(p) => void onCellChange('admin', p)}
              />
            </div>
          </div>
        </>
      )}
    </div>
  )
}

function TeachersGrid({
  sections,
  sundays,
  noSchoolSet,
  isCurrentYear,
  onCellChange,
}: {
  sections: StaffMonthlySection[]
  sundays: string[]
  noSchoolSet: Set<string>
  isCurrentYear: boolean
  onCellChange: (p: {
    userId: string
    date: string
    status: string
    roleName: string
    sectionCode?: string | null
  }) => void
}) {
  if (!sections.length) {
    return <div className="alert alert-info mb-0">No sections with assigned teachers found for this term.</div>
  }

  return (
    <table className="table table-bordered table-striped month-grid align-middle">
      <thead>
        <tr>
          <th className="sticky-col" style={{ minWidth: 180 }}>
            Class / Section
          </th>
          <th className="sticky-col-2" style={{ minWidth: 280 }}>
            Teacher
          </th>
          <th className="sticky-col-3 text-center" style={{ minWidth: 120 }}>
            Role
          </th>
          {sundays.map((day) => (
            <th
              key={day}
              className={`text-center${noSchoolSet.has(day) ? ' no-school-day' : ''}`}
              style={{ minWidth: 56 }}
              title={day}
            >
              {day.slice(5, 7)}-{day.slice(8, 10)}
            </th>
          ))}
          <th className="text-center" style={{ minWidth: 70 }}>
            P
          </th>
          <th className="text-center" style={{ minWidth: 70 }}>
            A
          </th>
          <th className="text-center" style={{ minWidth: 70 }}>
            L
          </th>
        </tr>
      </thead>
      <tbody>
        {sections.flatMap((section) => {
          const teachers = section.teachers ?? []
          const rowSpan = teachers.length || 1
          if (!teachers.length) return []
          return teachers.map((teacher, t) => (
            <TeacherRow
              key={`${section.section_code}-${teacher.user_id ?? teacher.teacher_id}-${t}`}
              section={section}
              teacher={teacher}
              tIndex={t}
              rowSpan={rowSpan}
              sundays={sundays}
              noSchoolSet={noSchoolSet}
              isCurrentYear={isCurrentYear}
              onCellChange={onCellChange}
            />
          ))
        })}
      </tbody>
    </table>
  )
}

function TeacherRow({
  section,
  teacher,
  tIndex,
  rowSpan,
  sundays,
  noSchoolSet,
  isCurrentYear,
  onCellChange,
}: {
  section: StaffMonthlySection
  teacher: StaffMonthlyTeacherRow
  tIndex: number
  rowSpan: number
  sundays: string[]
  noSchoolSet: Set<string>
  isCurrentYear: boolean
  onCellChange: (p: {
    userId: string
    date: string
    status: string
    roleName: string
    sectionCode?: string | null
  }) => void
}) {
  const uid = String(teacher.user_id ?? teacher.teacher_id ?? '')
  const roleText =
    String(teacher.position ?? '').toLowerCase() === 'main' ? 'Main' : 'Assistant'
  const totals = teacher.totals ?? {}

  return (
    <tr>
      {tIndex === 0 ? (
        <td className="sticky-col" rowSpan={rowSpan} style={{ minWidth: 180 }}>
          {section.label ?? section.section_code ?? '—'}
        </td>
      ) : null}
      <td className="sticky-col-2">{teacher.name ?? '—'}</td>
      <td className="sticky-col-3 text-center">{roleText}</td>
      {sundays.map((day) => {
        if (noSchoolSet.has(day)) {
          return (
            <td key={day} className="text-center no-school-day">
              <span className="badge-cell bg-info text-dark">NS</span>
            </td>
          )
        }
        const st = String(teacher.cells?.[day]?.status ?? '').toLowerCase()
        const val = st === 'present' || st === 'absent' || st === 'late' ? st : ''
        return (
          <td key={day} className="text-center">
            <select
              disabled={!isCurrentYear}
              className={selectClass(val)}
              value={val}
              onChange={(ev) =>
                onCellChange({
                  userId: uid,
                  date: day,
                  status: ev.target.value,
                  roleName: roleText,
                  sectionCode: section.section_code ?? null,
                })
              }
            >
              <option value="">—</option>
              <option value="present">P</option>
              <option value="absent">A</option>
              <option value="late">L</option>
            </select>
          </td>
        )
      })}
      <td className="text-center">
        <strong>{totals.p ?? 0}</strong>
      </td>
      <td className="text-center">
        <strong>{totals.a ?? 0}</strong>
      </td>
      <td className="text-center">
        <strong>{totals.l ?? 0}</strong>
      </td>
    </tr>
  )
}

function AdminsGrid({
  admins,
  sundays,
  noSchoolSet,
  isCurrentYear,
  onCellChange,
}: {
  admins: StaffMonthlyAdminRow[]
  sundays: string[]
  noSchoolSet: Set<string>
  isCurrentYear: boolean
  onCellChange: (p: {
    userId: string
    date: string
    status: string
    roleName: string
    sectionCode?: string | null
  }) => void
}) {
  if (!admins.length) {
    return <div className="alert alert-info mb-0">No admin users found for this term.</div>
  }

  return (
    <table className="table table-bordered table-striped month-grid align-middle">
      <thead>
        <tr>
          <th className="sticky-col" style={{ minWidth: 180 }}>
            Admin
          </th>
          <th className="sticky-col-2 text-center" style={{ minWidth: 240 }}>
            Role
          </th>
          {sundays.map((day) => (
            <th
              key={day}
              className={`text-center${noSchoolSet.has(day) ? ' no-school-day' : ''}`}
              style={{ minWidth: 56 }}
              title={day}
            >
              {day.slice(5, 7)}-{day.slice(8, 10)}
            </th>
          ))}
          <th className="text-center">P</th>
          <th className="text-center">A</th>
          <th className="text-center">L</th>
        </tr>
      </thead>
      <tbody>
        {admins.map((admin) => {
          const uid = String(admin.user_id ?? '')
          const totals = admin.totals ?? {}
          return (
            <tr key={uid}>
              <td className="sticky-col">{admin.name ?? '—'}</td>
              <td className="sticky-col-2 text-center">{admin.role ?? '—'}</td>
              {sundays.map((day) => {
                if (noSchoolSet.has(day)) {
                  return (
                    <td key={day} className="text-center no-school-day">
                      <span className="badge-cell bg-info text-dark">NS</span>
                    </td>
                  )
                }
                const st = String(admin.cells?.[day]?.status ?? '').toLowerCase()
                const val = st === 'present' || st === 'absent' || st === 'late' ? st : ''
                return (
                  <td key={day} className="text-center">
                    <select
                      disabled={!isCurrentYear}
                      className={selectClass(val)}
                      value={val}
                      onChange={(ev) =>
                        onCellChange({
                          userId: uid,
                          date: day,
                          status: ev.target.value,
                          roleName: admin.role ?? 'Admin',
                        })
                      }
                    >
                      <option value="">—</option>
                      <option value="present">P</option>
                      <option value="absent">A</option>
                      <option value="late">L</option>
                    </select>
                  </td>
                )
              })}
              <td className="text-center">
                <strong>{totals.p ?? 0}</strong>
              </td>
              <td className="text-center">
                <strong>{totals.a ?? 0}</strong>
              </td>
              <td className="text-center">
                <strong>{totals.l ?? 0}</strong>
              </td>
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}
