import { type FormEvent, useEffect, useMemo, useRef, useState } from 'react'
import { Link } from 'react-router-dom'
import { fetchUsers, saveUser } from '../../api/session'
import type { UserListRow } from '../../api/types'

function dash(v: unknown): string {
  const s = (v ?? '').toString().trim()
  return s === '' ? '—' : s
}

function formatDateTimeLocal(value: unknown): string {
  if (value == null || value === '') return ''
  const normalized = String(value).trim().replace(' ', 'T')
  const date = new Date(normalized)
  if (Number.isNaN(date.valueOf())) {
    const match = normalized.match(/^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2})/)
    return match ? `${match[1]}T${match[2]}` : ''
  }
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`
}

function roleLabels(row: UserListRow): string {
  const roles = row.roles
  if (!roles?.length) return 'No Role Assigned'
  const parts = roles
    .map((r) => {
      if (typeof r === 'string') return r.trim()
      return String(r.name ?? r.slug ?? '').trim()
    })
    .filter(Boolean)
  return parts.length ? parts.join(', ') : 'No Role Assigned'
}

function isParentRole(row: UserListRow): boolean {
  return (row.roles ?? []).some((r) => {
    const s =
      typeof r === 'string' ? r.toLowerCase() : `${r.name ?? ''} ${r.slug ?? ''}`.toLowerCase()
    return s.includes('parent')
  })
}

type EditFormState = {
  id: number
  account_id: string
  firstname: string
  lastname: string
  gender: string
  cellphone: string
  email: string
  address_street: string
  apt: string
  city: string
  state: string
  zip: string
  accept_school_policy: boolean
  user_type: string
  rfid_tag: string
  school_id: string
  failed_attempts: string
  last_failed_at: string
  semester: string
  school_year: string
  status: string
  is_suspended: boolean
  is_verified: boolean
  token: string
  updated_at: string
  created_at: string
}

function userToForm(user: Record<string, unknown>, id: number): EditFormState {
  const g = (user.gender ?? '').toString().toLowerCase()
  return {
    id,
    account_id: String(user.account_id ?? ''),
    firstname: String(user.firstname ?? ''),
    lastname: String(user.lastname ?? ''),
    gender: g === 'male' || g === 'female' ? g : '',
    cellphone: String(user.cellphone ?? ''),
    email: String(user.email ?? ''),
    address_street: String(user.address_street ?? ''),
    apt: String(user.apt ?? ''),
    city: String(user.city ?? ''),
    state: String(user.state ?? ''),
    zip: String(user.zip ?? ''),
    accept_school_policy: Boolean(
      user.accept_school_policy === true ||
        user.accept_school_policy === 1 ||
        user.accept_school_policy === '1',
    ),
    user_type: String(user.user_type ?? ''),
    rfid_tag: String(user.rfid_tag ?? ''),
    school_id: String(user.school_id ?? ''),
    failed_attempts: String(user.failed_attempts ?? ''),
    last_failed_at: formatDateTimeLocal(user.last_failed_at),
    semester: String(user.semester ?? ''),
    school_year: String(user.school_year ?? ''),
    status: String(user.status ?? ''),
    is_suspended: Boolean(
      user.is_suspended === true || user.is_suspended === 1 || user.is_suspended === '1',
    ),
    is_verified: Boolean(
      user.is_verified === true || user.is_verified === 1 || user.is_verified === '1',
    ),
    token: String(user.token ?? ''),
    updated_at: formatDateTimeLocal(user.updated_at),
    created_at: formatDateTimeLocal(user.created_at),
  }
}

function formToPayload(f: EditFormState): Record<string, unknown> {
  const payload: Record<string, unknown> = {
    firstname: f.firstname.trim(),
    lastname: f.lastname.trim(),
    accept_school_policy: f.accept_school_policy ? 1 : 0,
    is_suspended: f.is_suspended ? 1 : 0,
    is_verified: f.is_verified ? 1 : 0,
  }
  const normalizedGender = f.gender.trim().toLowerCase()
  const normalizedUserType = f.user_type.trim().toLowerCase()
  const normalizedStatus = f.status.trim().toLowerCase()

  const assignIfPresent = (key: string, value: string, opts?: { nullable?: boolean }) => {
    const trimmed = value.trim()
    if (trimmed !== '') {
      payload[key] = trimmed
      return
    }
    if (opts?.nullable) {
      payload[key] = null
    }
  }

  assignIfPresent('account_id', f.account_id, { nullable: true })
  assignIfPresent('cellphone', f.cellphone)
  assignIfPresent('email', f.email)
  assignIfPresent('address_street', f.address_street)
  assignIfPresent('apt', f.apt, { nullable: true })
  assignIfPresent('city', f.city)
  assignIfPresent('state', f.state)
  assignIfPresent('zip', f.zip)
  assignIfPresent('rfid_tag', f.rfid_tag, { nullable: true })
  assignIfPresent('last_failed_at', f.last_failed_at, { nullable: true })
  assignIfPresent('semester', f.semester)
  assignIfPresent('school_year', f.school_year, { nullable: true })
  assignIfPresent('token', f.token, { nullable: true })

  if (normalizedGender === 'male' || normalizedGender === 'female') {
    payload.gender = normalizedGender
  } else if (normalizedGender === '') {
    payload.gender = null
  }

  if (normalizedUserType === 'primary' || normalizedUserType === 'secondary' || normalizedUserType === 'tertiary') {
    payload.user_type = normalizedUserType
  }

  if (normalizedStatus === 'active' || normalizedStatus === 'inactive') {
    payload.status = normalizedStatus === 'active' ? 'Active' : 'Inactive'
  }

  const schoolId = f.school_id.trim()
  if (schoolId !== '') {
    if (/^\d+$/.test(schoolId)) {
      payload.school_id = Number(schoolId)
    }
  } else {
    payload.school_id = null
  }

  const failedAttempts = f.failed_attempts.trim()
  payload.failed_attempts = failedAttempts === '' ? null : Number(failedAttempts)

  return payload
}

function buildChangedPayload(
  current: EditFormState,
  original: EditFormState | null,
): Record<string, unknown> {
  const currentPayload = formToPayload(current)
  if (!original) return currentPayload

  const originalPayload = formToPayload(original)
  const changed: Record<string, unknown> = {}

  for (const [key, value] of Object.entries(currentPayload)) {
    if (!Object.is(value, originalPayload[key])) {
      changed[key] = value
    }
  }

  return changed
}

type SortCol = 'id' | 'firstname' | 'lastname' | 'email' | 'cellphone' | 'user_type' | 'roles'

function sortValue(entry: UserListRow, col: SortCol): string | number {
  const u = entry.user ?? {}
  switch (col) {
    case 'id':
      return Number(u.school_id ?? u.id ?? 0)
    case 'roles':
      return roleLabels(entry).toLowerCase()
    default:
      return String(u[col] ?? '').toLowerCase()
  }
}

function SortTh({
  col, label, sortCol, sortDir, onSort, style,
}: {
  col: SortCol; label: string; sortCol: SortCol; sortDir: 'asc' | 'desc'
  onSort: (c: SortCol) => void; style?: React.CSSProperties
}) {
  const active = sortCol === col
  return (
    <th
      style={{ cursor: 'pointer', userSelect: 'none', whiteSpace: 'nowrap', ...style }}
      onClick={() => onSort(col)}
    >
      {label}{' '}
      <span style={{ opacity: active ? 1 : 0.3 }}>
        {active && sortDir === 'desc' ? '▼' : '▲'}
      </span>
    </th>
  )
}

/** CI `user/user_list.php` — DataTable-style list + full edit modal (`saveUser`). */
export function UserListPage() {
  const [rows, setRows] = useState<UserListRow[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [saveError, setSaveError] = useState<string | null>(null)
  const [form, setForm] = useState<EditFormState | null>(null)
  const [originalForm, setOriginalForm] = useState<EditFormState | null>(null)
  const [saving, setSaving] = useState(false)
  const modalRef = useRef<HTMLDivElement | null>(null)
  const [sortCol, setSortCol] = useState<SortCol>('lastname')
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc')

  async function load() {
    setLoading(true)
    try {
      const data = await fetchUsers({ sort: 'lastname', order: 'asc' })
      setRows(data.users ?? [])
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load users.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  function handleSort(col: SortCol) {
    if (col === sortCol) {
      setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'))
    } else {
      setSortCol(col)
      setSortDir('asc')
    }
  }

  const sortedRows = useMemo(() => {
    const copy = [...rows]
    copy.sort((a, b) => {
      const av = sortValue(a, sortCol)
      const bv = sortValue(b, sortCol)
      if (av < bv) return sortDir === 'asc' ? -1 : 1
      if (av > bv) return sortDir === 'asc' ? 1 : -1
      return 0
    })
    return copy
  }, [rows, sortCol, sortDir])

  const modalTitle = useMemo(() => {
    if (!form) return 'Edit User'
    const name = [form.firstname, form.lastname].filter(Boolean).join(' ').trim()
    return name ? `Edit User — ${name}` : 'Edit User'
  }, [form])

  useEffect(() => {
    if (!form) return
    const el = modalRef.current
    const B = (
      window as unknown as {
        bootstrap?: { Modal: { getOrCreateInstance: (n: HTMLElement) => { show: () => void } } }
      }
    ).bootstrap
    if (el && B?.Modal?.getOrCreateInstance) {
      B.Modal.getOrCreateInstance(el).show()
    }
  }, [form])

  function openEdit(entry: UserListRow) {
    const user = entry.user ?? {}
    const id = Number(user.id ?? 0)
    if (!id) return
    const nextForm = userToForm(user as Record<string, unknown>, id)
    setSaveError(null)
    setOriginalForm(nextForm)
    setForm(nextForm)
  }

  function closeModal() {
    const el = modalRef.current
    const Inst = (
      window as unknown as {
        bootstrap?: { Modal: { getInstance: (n: HTMLElement) => { hide: () => void } | null } }
      }
    ).bootstrap?.Modal
    if (el && Inst?.getInstance) {
      Inst.getInstance(el)?.hide()
    }
    setForm(null)
    setOriginalForm(null)
  }

  async function onSubmit(e: FormEvent) {
    e.preventDefault()
    if (!form) return
    const payload = buildChangedPayload(form, originalForm)
    if (Object.keys(payload).length === 0) {
      setSaveError(null)
      closeModal()
      return
    }
    setSaving(true)
    setSaveError(null)
    try {
      await saveUser(form.id, payload)
      await load()
      closeModal()
    } catch (err) {
      setSaveError(err instanceof Error ? err.message : 'Save failed.')
    } finally {
      setSaving(false)
    }
  }

  return (
    <div className="container-fluid py-3">
      <div className="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
        <h2 className="text-center mt-2 mb-0 flex-grow-1">User List</h2>
        <Link className="btn btn-success btn-sm" to="/app/user/create">
          Create user
        </Link>
      </div>

      {error ? (
        <div id="userListAlert" className="alert alert-danger" role="alert">
          {error}
        </div>
      ) : null}

      <div className="table-responsive">
        <table className="display table table-striped table-bordered align-middle" style={{ width: '100%' }}>
          <thead className="table-dark">
            <tr>
              <SortTh col="id"         label="ID"        sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="firstname"  label="First Name" sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="lastname"   label="Last Name"  sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="email"      label="Email"     sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="cellphone"  label="Phone"     sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="user_type"  label="User Type" sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="roles"      label="Roles"     sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <th style={{ width: 140 }}>Actions</th>
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr>
                <td colSpan={8} className="text-center text-muted">
                  Loading users…
                </td>
              </tr>
            ) : rows.length === 0 ? (
              <tr>
                <td colSpan={8} className="text-center text-muted">
                  No users found.
                </td>
              </tr>
            ) : (
              sortedRows.map((entry) => {
                const user = entry.user ?? {}
                const uid = Number(user.id ?? 0)
                const idDisplay =
                  user.school_id != null && String(user.school_id).trim() !== ''
                    ? String(user.school_id)
                    : String(user.id ?? '')
                const parent = isParentRole(entry) && uid > 0
                const familyHref = `/app/administrator/family?guardian_id=${encodeURIComponent(String(uid))}`

                return (
                  <tr key={uid || idDisplay}>
                    <td>{dash(idDisplay)}</td>
                    <td>
                      {parent ? (
                        <Link className="text-decoration-none" to={familyHref}>
                          {dash(user.firstname)}
                        </Link>
                      ) : (
                        dash(user.firstname)
                      )}
                    </td>
                    <td>
                      {parent ? (
                        <Link className="text-decoration-none" to={familyHref}>
                          {dash(user.lastname)}
                        </Link>
                      ) : (
                        dash(user.lastname)
                      )}
                    </td>
                    <td>
                      {user.email ? (
                        <a className="text-decoration-none" href={`mailto:${String(user.email)}`}>
                          {String(user.email)}
                        </a>
                      ) : (
                        '—'
                      )}
                    </td>
                    <td>
                      {user.cellphone ? (
                        <a className="text-decoration-none" href={`tel:${String(user.cellphone)}`}>
                          {String(user.cellphone)}
                        </a>
                      ) : (
                        '—'
                      )}
                    </td>
                    <td>{dash(user.user_type)}</td>
                    <td>{roleLabels(entry)}</td>
                    <td>
                      <button
                        type="button"
                        className="btn btn-sm btn-primary"
                        disabled={!uid}
                        onClick={() => openEdit(entry)}
                      >
                        <i className="fas fa-edit" aria-hidden /> Edit
                      </button>
                    </td>
                  </tr>
                )
              })
            )}
          </tbody>
        </table>
      </div>

      {form ? (
        <div
          className="modal fade"
          id="editUserModal"
          tabIndex={-1}
          ref={modalRef}
          aria-labelledby="editUserModalLabel"
          aria-hidden="true"
        >
          <div className="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
            <form className="modal-content" onSubmit={(e) => void onSubmit(e)}>
              <div className="modal-header bg-primary text-white">
                <h5 className="modal-title" id="editUserModalLabel">
                  {modalTitle}
                </h5>
                <button
                  type="button"
                  className="btn-close btn-close-white"
                  aria-label="Close"
                  onClick={() => closeModal()}
                />
              </div>

              <div className="modal-body">
                {saveError ? <div className="alert alert-danger">{saveError}</div> : null}
                <div className="row g-3">
                  <div className="col-md-6">
                    <div className="mb-3">
                      <label className="form-label">Account ID</label>
                      <input
                        type="text"
                        name="account_id"
                        className="form-control"
                        value={form.account_id}
                        onChange={(e) => setForm((c) => (c ? { ...c, account_id: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">First Name</label>
                      <input
                        type="text"
                        name="firstname"
                        className="form-control"
                        required
                        value={form.firstname}
                        onChange={(e) => setForm((c) => (c ? { ...c, firstname: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Last Name</label>
                      <input
                        type="text"
                        name="lastname"
                        className="form-control"
                        required
                        value={form.lastname}
                        onChange={(e) => setForm((c) => (c ? { ...c, lastname: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Gender</label>
                      <select
                        name="gender"
                        className="form-select"
                        value={form.gender}
                        onChange={(e) => setForm((c) => (c ? { ...c, gender: e.target.value } : c))}
                      >
                        <option value="">—</option>
                        <option value="male">Male</option>
                        <option value="female">Female</option>
                      </select>
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Phone</label>
                      <input
                        type="text"
                        name="cellphone"
                        className="form-control"
                        value={form.cellphone}
                        onChange={(e) => setForm((c) => (c ? { ...c, cellphone: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Email</label>
                      <input
                        type="email"
                        name="email"
                        className="form-control"
                        required
                        value={form.email}
                        onChange={(e) => setForm((c) => (c ? { ...c, email: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Address Street</label>
                      <input
                        type="text"
                        name="address_street"
                        className="form-control"
                        value={form.address_street}
                        onChange={(e) => setForm((c) => (c ? { ...c, address_street: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Apt</label>
                      <input
                        type="text"
                        name="apt"
                        className="form-control"
                        value={form.apt}
                        onChange={(e) => setForm((c) => (c ? { ...c, apt: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">City</label>
                      <input
                        type="text"
                        name="city"
                        className="form-control"
                        value={form.city}
                        onChange={(e) => setForm((c) => (c ? { ...c, city: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">State</label>
                      <input
                        type="text"
                        name="state"
                        maxLength={2}
                        className="form-control"
                        value={form.state}
                        onChange={(e) => setForm((c) => (c ? { ...c, state: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">ZIP</label>
                      <input
                        type="text"
                        name="zip"
                        className="form-control"
                        value={form.zip}
                        onChange={(e) => setForm((c) => (c ? { ...c, zip: e.target.value } : c))}
                      />
                    </div>
                  </div>

                  <div className="col-md-6">
                    <div className="mb-3">
                      <label className="form-label d-block">Accept School Policy</label>
                      <div className="form-check form-switch">
                        <input
                          className="form-check-input"
                          type="checkbox"
                          checked={form.accept_school_policy}
                          onChange={(e) =>
                            setForm((c) => (c ? { ...c, accept_school_policy: e.target.checked } : c))
                          }
                        />
                        <label className="form-check-label">Accepted</label>
                      </div>
                    </div>
                    <div className="mb-3">
                      <label className="form-label">User Type</label>
                      <input
                        type="text"
                        name="user_type"
                        className="form-control"
                        value={form.user_type}
                        onChange={(e) => setForm((c) => (c ? { ...c, user_type: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">RFID Tag</label>
                      <input
                        type="text"
                        name="rfid_tag"
                        className="form-control"
                        value={form.rfid_tag}
                        onChange={(e) => setForm((c) => (c ? { ...c, rfid_tag: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">School ID</label>
                      <input
                        type="text"
                        name="school_id"
                        className="form-control"
                        value={form.school_id}
                        onChange={(e) => setForm((c) => (c ? { ...c, school_id: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Failed Attempts</label>
                      <input
                        type="number"
                        name="failed_attempts"
                        className="form-control"
                        value={form.failed_attempts}
                        onChange={(e) => setForm((c) => (c ? { ...c, failed_attempts: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Last Failed At</label>
                      <input
                        type="datetime-local"
                        name="last_failed_at"
                        className="form-control"
                        value={form.last_failed_at}
                        onChange={(e) => setForm((c) => (c ? { ...c, last_failed_at: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Semester</label>
                      <input
                        type="text"
                        name="semester"
                        className="form-control"
                        value={form.semester}
                        onChange={(e) => setForm((c) => (c ? { ...c, semester: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">School Year</label>
                      <input
                        type="text"
                        name="school_year"
                        className="form-control"
                        value={form.school_year}
                        onChange={(e) => setForm((c) => (c ? { ...c, school_year: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Status</label>
                      <input
                        type="text"
                        name="status"
                        className="form-control"
                        value={form.status}
                        onChange={(e) => setForm((c) => (c ? { ...c, status: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label d-block">Is Suspended</label>
                      <div className="form-check form-switch">
                        <input
                          className="form-check-input"
                          type="checkbox"
                          checked={form.is_suspended}
                          onChange={(e) =>
                            setForm((c) => (c ? { ...c, is_suspended: e.target.checked } : c))
                          }
                        />
                        <label className="form-check-label">Suspended</label>
                      </div>
                    </div>
                    <div className="mb-3">
                      <label className="form-label d-block">Is Verified</label>
                      <div className="form-check form-switch">
                        <input
                          className="form-check-input"
                          type="checkbox"
                          checked={form.is_verified}
                          onChange={(e) =>
                            setForm((c) => (c ? { ...c, is_verified: e.target.checked } : c))
                          }
                        />
                        <label className="form-check-label">Verified</label>
                      </div>
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Token</label>
                      <input
                        type="text"
                        name="token"
                        className="form-control"
                        value={form.token}
                        onChange={(e) => setForm((c) => (c ? { ...c, token: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Updated At</label>
                      <input
                        type="datetime-local"
                        name="updated_at"
                        className="form-control"
                        value={form.updated_at}
                        onChange={(e) => setForm((c) => (c ? { ...c, updated_at: e.target.value } : c))}
                      />
                    </div>
                    <div className="mb-3">
                      <label className="form-label">Created At</label>
                      <input
                        type="datetime-local"
                        name="created_at"
                        className="form-control"
                        value={form.created_at}
                        onChange={(e) => setForm((c) => (c ? { ...c, created_at: e.target.value } : c))}
                      />
                    </div>
                  </div>
                </div>
              </div>

              <div className="modal-footer">
                <button type="button" className="btn btn-secondary" onClick={() => closeModal()}>
                  Cancel
                </button>
                <button type="submit" className="btn btn-primary" disabled={saving}>
                  {saving ? 'Saving…' : 'Save Changes'}
                </button>
              </div>
            </form>
          </div>
        </div>
      ) : null}
    </div>
  )
}
