import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { ApiHttpError } from '../../api/http'
import type { FamilyAdminIndexResponse, FamilyRow, FamilySearchSuggestionItem } from '../../api/types'
import { fetchFamilyAdminIndex, fetchFamilySearchSuggestions } from '../../api/session'
import { FamilyCardBody } from './FamilyCardBody'
import { FamilyListCard } from './FamilyListCard'
import { familyCardMatches, familySearchBlob, normalize } from './familyUtils'

function parsePositiveInt(s: string | null): number | undefined {
  if (s == null || s === '') return undefined
  const n = Number.parseInt(s, 10)
  return Number.isFinite(n) && n > 0 ? n : undefined
}

function buildStaticSuggestions(
  q: string,
  data: FamilyAdminIndexResponse['data'],
): FamilySearchSuggestionItem[] {
  if (!data) return []
  const qn = normalize(q)
  const out: FamilySearchSuggestionItem[] = []
  for (const st of data.searchStudents ?? []) {
    const id = Number((st as Record<string, unknown>).id ?? 0)
    if (!id) continue
    const sf = String((st as Record<string, unknown>).firstname ?? '').trim()
    const sl = String((st as Record<string, unknown>).lastname ?? '').trim()
    const slab = `${sf} ${sl}`.trim()
    if (normalize(slab).includes(qn)) {
      out.push({ type: 'student', id, label: slab || `Student #${id}`, sub: 'Student' })
    }
  }
  for (const gu of data.searchGuardians ?? []) {
    const id = Number(gu.id ?? 0)
    if (!id) continue
    const gf = String(gu.firstname ?? '').trim()
    const gl = String(gu.lastname ?? '').trim()
    const glab = `${gf} ${gl}`.trim()
    const gel = String(gu.email ?? '').trim()
    const gph = String((gu as Record<string, unknown>).cellphone ?? '').trim()
    const gsub = `${gel} ${gph}`.trim()
    if (normalize(glab).includes(qn) || normalize(gsub).includes(qn)) {
      out.push({ type: 'guardian', id, label: glab || `Guardian #${id}`, sub: gsub })
    }
  }
  return out.slice(0, 12)
}

export function FamilyManagementPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const studentId = parsePositiveInt(searchParams.get('student_id'))
  const guardianId = parsePositiveInt(searchParams.get('guardian_id'))

  const [payload, setPayload] = useState<FamilyAdminIndexResponse | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [searchInput, setSearchInput] = useState('')
  const [suggestions, setSuggestions] = useState<FamilySearchSuggestionItem[]>([])
  const [suggestOpen, setSuggestOpen] = useState(false)
  const [modalFamily, setModalFamily] = useState<FamilyRow | null>(null)
  const suggestTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
  const searchWrapRef = useRef<HTMLDivElement | null>(null)

  const returnUrl = `${window.location.pathname}${window.location.search}`

  useEffect(() => {
    let cancelled = false
    setLoading(true)
    fetchFamilyAdminIndex({
      studentId: studentId ?? null,
      guardianId: guardianId ?? null,
    })
      .then((d) => {
        if (!cancelled) {
          setPayload(d)
          setError(null)
        }
      })
      .catch((e: unknown) => {
        if (!cancelled)
          setError(e instanceof ApiHttpError ? e.message : 'Unable to load families.')
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [studentId, guardianId])

  const families = payload?.data?.families ?? []
  const studentBanner = payload?.data?.student

  const filteredFamilies = useMemo(() => {
    const q = searchInput.trim()
    return families.filter((f) => familyCardMatches(f, q))
  }, [families, searchInput])

  const anyVisible = filteredFamilies.length > 0 || searchInput.trim() === ''

  const refreshSuggestions = useCallback(
    async (q: string) => {
      const qt = q.trim()
      if (qt.length < 1) {
        setSuggestions([])
        setSuggestOpen(false)
        return
      }
      const api = await fetchFamilySearchSuggestions(qt)
      let items = api.items ?? []
      if (items.length === 0 && payload?.data) {
        items = buildStaticSuggestions(qt, payload.data)
      }
      setSuggestions(items.slice(0, 8))
      setSuggestOpen(items.length > 0)
    },
    [payload],
  )

  useEffect(() => {
    if (suggestTimer.current) clearTimeout(suggestTimer.current)
    const q = searchInput.trim()
    if (q.length < 1) {
      setSuggestions([])
      setSuggestOpen(false)
      return
    }
    suggestTimer.current = setTimeout(() => {
      void refreshSuggestions(q)
    }, 150)
    return () => {
      if (suggestTimer.current) clearTimeout(suggestTimer.current)
    }
  }, [searchInput, refreshSuggestions])

  useEffect(() => {
    function onDocClick(e: MouseEvent) {
      const el = searchWrapRef.current
      if (!el || !(e.target instanceof Node)) return
      if (!el.contains(e.target)) setSuggestOpen(false)
    }
    document.addEventListener('click', onDocClick)
    return () => document.removeEventListener('click', onDocClick)
  }, [])

  function pickSuggestion(it: FamilySearchSuggestionItem) {
    setSuggestOpen(false)
    setSearchInput('')
    const next = new URLSearchParams(searchParams)
    if (it.type === 'student') {
      next.set('student_id', String(it.id))
      next.delete('guardian_id')
    } else {
      next.set('guardian_id', String(it.id))
      next.delete('student_id')
    }
    setSearchParams(next)
  }

  return (
    <div className="container-fluid my-4">
      <div className="d-flex flex-wrap justify-content-center align-items-center gap-2 mb-3">
        <h2 className="text-center mt-4 mb-0 flex-grow-1">Family Management</h2>
        <Link className="btn btn-outline-secondary btn-sm" to="/app/families/import-legacy">
          Import legacy
        </Link>
      </div>

      {loading ? <p className="text-muted text-center">Loading…</p> : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}

      <div className="row mb-3 justify-content-center">
        <div className="col-12 col-md-8 col-lg-6 position-relative mx-auto" ref={searchWrapRef}>
          <label htmlFor="familySearch" className="form-label">
            Search (parent, student, phone, email)
          </label>
          <input
            type="search"
            className="form-control"
            id="familySearch"
            placeholder="Type to filter…"
            autoComplete="off"
            aria-autocomplete="list"
            aria-haspopup="listbox"
            value={searchInput}
            onChange={(e) => setSearchInput(e.target.value)}
            onFocus={() => {
              const v = searchInput.trim()
              if (v.length >= 1) void refreshSuggestions(v)
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter' && suggestOpen && suggestions.length > 0) {
                e.preventDefault()
                pickSuggestion(suggestions[0])
              }
            }}
          />
          {suggestOpen && suggestions.length > 0 ? (
            <div
              className="list-group position-absolute w-100"
              style={{ zIndex: 1030, maxHeight: 260, overflow: 'auto' }}
              role="listbox"
            >
              {suggestions.map((it) => (
                <button
                  key={`${it.type}-${it.id}`}
                  type="button"
                  className="list-group-item list-group-item-action"
                  onClick={() => pickSuggestion(it)}
                >
                  <div className="d-flex justify-content-between gap-2">
                    <span>{it.label}</span>
                    <span className="text-muted small">{it.sub ?? ''}</span>
                  </div>
                </button>
              ))}
            </div>
          ) : null}
        </div>
      </div>

      {!anyVisible && searchInput.trim() !== '' ? (
        <div className="alert alert-warning">No matches found.</div>
      ) : null}

      {studentBanner ? (
        <div className="card mb-3">
          <div className="card-header">Student</div>
          <div className="card-body">
            <strong>
              {String(studentBanner.firstname ?? '').trim()}{' '}
              {String(studentBanner.lastname ?? '').trim()}
            </strong>
          </div>
        </div>
      ) : null}

      {!loading && families.length === 0 ? (
        <div className="alert alert-warning">No families found.</div>
      ) : null}

      {filteredFamilies.map((f) => (
        <FamilyListCard
          key={f.id}
          family={f}
          searchBlobAttr={familySearchBlob(f)}
          onOpenDetails={() => setModalFamily(f)}
        />
      ))}

      {modalFamily ? (
        <div
          className="modal fade show d-block"
          tabIndex={-1}
          role="dialog"
          aria-modal="true"
          style={{ backgroundColor: 'rgba(0, 0, 0, 0.35)' }}
          onClick={() => setModalFamily(null)}
          onKeyDown={(e) => {
            if (e.key === 'Escape') setModalFamily(null)
          }}
        >
          <div
            className="modal-dialog modal-xl modal-dialog-scrollable"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="modal-content">
              <div className="modal-header">
                <h5 className="modal-title">Family</h5>
                <button
                  type="button"
                  className="btn-close"
                  aria-label="Close"
                  onClick={() => setModalFamily(null)}
                />
              </div>
              <div className="modal-body">
                <FamilyCardBody family={modalFamily} returnUrl={returnUrl} />
              </div>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  )
}
