'use client';

import { FormEvent, useEffect, useRef, useState } from 'react';
import { MAX_VOTER_IMAGE_SIZE, RegisteredVoter, RegisteredVoterPage, isRegisteredVoter, isRegisteredVoterPage } from '@/lib/registeredVoters';
import { isRecord } from '@/lib/users';
import { isBvasImage } from '@/lib/bvasInfo';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { EMPTY_GEOGRAPHY, GeographySelection, geographyFilterQuery } from '@/lib/geography';
import { GeographyFilterCards } from './GeographyFields';

const input = 'min-h-11 w-full rounded-xl border border-slate-300 bg-white px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-700 focus-visible:ring-offset-2';
const buttonBase = 'inline-flex min-h-11 items-center justify-center rounded-xl border px-4 py-2 text-sm font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-700 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50';
const button = `${buttonBase} border-slate-300 bg-white text-slate-700 hover:bg-slate-100 active:bg-slate-200`;
const primaryButton = `${buttonBase} border-emerald-700 bg-emerald-700 text-white hover:bg-emerald-800 active:bg-emerald-900`;
const geographyColumns = [
  ['State', 'state_id'], ['LGA', 'lga_id'], ['Ward', 'ward_id'], ['Polling Unit', 'pu_id'],
] as const;

async function request(url: string, options: RequestInit = {}) {
  const response = await fetch(url, { ...options, cache: 'no-store' });
  if (response.status === 401) window.location.replace('/?screen=get_started');
  if (response.status === 204) return null;
  const data: unknown = await response.json();
  if (!response.ok) {
    const messages = isRecord(data) && isRecord(data.errors)
      ? Object.entries(data.errors).flatMap(([field, values]) =>
        Array.isArray(values) ? values.filter((value): value is string => typeof value === 'string').map((value) => `${field}: ${value}`) : []) : [];
    throw new Error(messages.length ? messages.join(' ') : isRecord(data) && typeof data.error === 'string' ? data.error : 'Unable to complete the registered-voters request.');
  }
  return data;
}

function message(error: unknown) { return error instanceof Error ? error.message : 'Unable to reach the registered-voters service.'; }

export function RegisteredVoters(props: { canDelete: boolean; canFilterGeography?: boolean }) {
  const [client] = useState(() => new QueryClient());
  return <QueryClientProvider client={client}><RegisteredVotersContent {...props} /></QueryClientProvider>;
}

function RegisteredVotersContent({ canDelete, canFilterGeography = false }: { canDelete: boolean; canFilterGeography?: boolean }) {
  const [geography, setGeography] = useState<GeographySelection>({ ...EMPTY_GEOGRAPHY });
  const [page, setPage] = useState(1);
  const [perPage, setPerPage] = useState(25);
  const [revision, setRevision] = useState(0);
  const [data, setData] = useState<RegisteredVoterPage | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [notice, setNotice] = useState('');
  const [creating, setCreating] = useState(false);
  const [busy, setBusy] = useState(false);
  const inFlight = useRef(false);
  const [detail, setDetail] = useState<RegisteredVoter | null>(null);
  const [detailId, setDetailId] = useState<string | null>(null);
  const [detailError, setDetailError] = useState('');
  const [detailRevision, setDetailRevision] = useState(0);
  const [imageError, setImageError] = useState('');
  const [deleting, setDeleting] = useState<string | null>(null);
  const [deleteConfirmation, setDeleteConfirmation] = useState('');
  const [deleteError, setDeleteError] = useState('');
  const deleteDialog = useRef<HTMLDialogElement>(null);
  const [formError, setFormError] = useState('');

  useEffect(() => {
    if (deleting && canDelete) {
      setDeleteConfirmation('');
      setDeleteError('');
      deleteDialog.current?.showModal();
    } else {
      deleteDialog.current?.close();
    }
  }, [deleting, canDelete]);

  useEffect(() => {
    const controller = new AbortController();
    setLoading(true); setError(''); setData(null);
    const query = canFilterGeography ? geographyFilterQuery(geography) : new URLSearchParams();
    query.set('page', String(page)); query.set('per_page', String(perPage));
    request(`/api/registered-voters?${query}`, { signal: controller.signal })
      .then((value) => {
        if (!isRegisteredVoterPage(value)) throw new Error('The service returned an invalid register.');
        if (!controller.signal.aborted) setData(value);
      }).catch((error) => { if (!controller.signal.aborted) setError(message(error)); })
      .finally(() => { if (!controller.signal.aborted) setLoading(false); });
    return () => controller.abort();
  }, [page, perPage, revision, geography, canFilterGeography]);

  useEffect(() => {
    setDetail(null); setDetailError(''); setImageError('');
    if (!detailId) return;
    const controller = new AbortController();
    request(`/api/registered-voters/${encodeURIComponent(detailId)}`, { signal: controller.signal })
      .then((value) => {
        if (!isRecord(value) || !isRegisteredVoter(value.data)) throw new Error('The service returned invalid record details.');
        if (!controller.signal.aborted) setDetail(value.data);
      }).catch((error) => { if (!controller.signal.aborted) setDetailError(message(error)); });
    return () => controller.abort();
  }, [detailId, detailRevision]);

  const create = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (inFlight.current) return;
    const form = event.currentTarget;
    const body = new FormData(form);
    const file = body.get('image');
    if (!(file instanceof File) || !file.size || file.size > MAX_VOTER_IMAGE_SIZE) {
      setFormError('Choose an image of at most 5120 KB.'); return;
    }
    inFlight.current = true; setBusy(true); setFormError(''); setNotice('');
    try {
      await request('/api/registered-voters', { method: 'POST', body });
      form.reset(); setCreating(false); setPage(1); setRevision((n) => n + 1);
      setNotice('Registered-voter record created.');
    } catch (error) { setFormError(message(error)); }
    finally { inFlight.current = false; setBusy(false); }
  };

  const remove = async () => {
    if (!canDelete || !deleting || deleteConfirmation !== 'delete' || inFlight.current) return;
    inFlight.current = true; setBusy(true); setDeleteError(''); setNotice('');
    try {
      await request(`/api/registered-voters/${encodeURIComponent(deleting)}`, { method: 'DELETE' });
      if (detailId === deleting) setDetailId(null);
      setDeleting(null);
      if (data?.data.length === 1 && page > 1) setPage(page - 1);
      else setRevision((n) => n + 1);
      setNotice('Registered-voter record deleted.');
    } catch (error) { setDeleteError(message(error)); }
    finally { inFlight.current = false; setBusy(false); }
  };

  return <section className="space-y-6 font-sans text-slate-900" aria-labelledby="registered-voters-heading">
    <header className="flex flex-wrap items-center justify-between gap-4">
      <div><h1 id="registered-voters-heading" className="text-2xl font-bold tracking-tight sm:text-3xl">Registered voters</h1><p className="mt-2 text-sm leading-6 text-slate-600">Voter counts and supporting records by polling unit.</p></div>
      <div className="flex flex-wrap gap-2">
        <button className={button} disabled={busy || loading} onClick={() => setRevision((n) => n + 1)}>Refresh</button>
        <button className={primaryButton} disabled={busy} onClick={() => { setCreating(true); setFormError(''); }}>Add record</button>
      </div>
    </header>
    {canFilterGeography && <>
      <GeographyFilterCards subject="registered voters" value={geography} onChange={(next) => { setGeography(next); setPage(1); }} />
      <button className={button} onClick={() => { setGeography({ ...EMPTY_GEOGRAPHY }); setPage(1); }}>Clear geography filters</button>
    </>}
    {notice && <p role="status" className="rounded-lg bg-emerald-50 p-3 text-emerald-900">{notice}</p>}
    {error && <div role="alert" className="rounded-lg bg-rose-50 p-3 text-rose-800">{error} <button className={button} onClick={() => setRevision((n) => n + 1)}>Retry list</button></div>}
    {creating && <form onSubmit={create} className="space-y-4 rounded-xl border bg-white p-5">
      <h2 className="text-lg font-bold">Add registered-voter record</h2>
      {formError && <p role="alert" className="text-rose-700">{formError}</p>}
      <fieldset disabled={busy} className="space-y-4">
        <div><label htmlFor="voter-numbers" className="mb-1 block text-sm font-semibold">Voter count</label><input className={input} id="voter-numbers" name="numbers" type="number" min="0" max="4294967295" step="1" required /></div>
        <div><label htmlFor="voter-note" className="mb-1 block text-sm font-semibold">Note (optional)</label><textarea className={input} id="voter-note" name="note" maxLength={5000} rows={3} /></div>
        <div><label htmlFor="voter-image" className="mb-1 block text-sm font-semibold">Supporting image</label><input className={input} id="voter-image" name="image" type="file" accept="image/jpeg,image/png,image/gif,image/webp" required /><p className="mt-1 text-sm text-slate-600">JPEG, PNG, GIF, or WebP. Maximum 5120 KB.</p></div>
        <div className="flex gap-2"><button className={button} type="submit">{busy ? 'Saving...' : 'Save record'}</button><button className={button} type="button" onClick={() => setCreating(false)}>Cancel</button></div>
      </fieldset>
    </form>}
    {detailId && <section aria-label="Registered-voter details" className="space-y-3 rounded-xl border bg-white p-5">
      <div className="flex justify-between gap-3"><h2 className="text-lg font-bold">Record details</h2><button className={button} onClick={() => setDetailId(null)}>Close details</button></div>
      {detailError ? <p role="alert" className="text-rose-700">{detailError} <button className={button} onClick={() => setDetailRevision((n) => n + 1)}>Retry details</button></p> : !detail ? <p role="status">Loading record...</p> : <>
        <dl className="grid gap-3 sm:grid-cols-2">
          {geographyColumns.map(([label, field]) => <div key={field}><dt className="text-sm text-slate-600">{label}</dt><dd className="break-words font-medium">{detail[field] ?? 'Not available'}</dd></div>)}
          <div><dt className="text-sm text-slate-600">Voter count</dt><dd className="font-semibold">{detail.numbers.toLocaleString()}</dd></div>
          <div><dt className="text-sm text-slate-600">Updated</dt><dd>{detail.updated_at || 'Not available'}</dd></div>
          <div className="sm:col-span-2"><dt className="text-sm text-slate-600">Note</dt><dd className="whitespace-pre-wrap break-words">{detail.note || 'No note'}</dd></div>
        </dl>
        {!detail.image ? <p className="text-sm text-slate-600">Supporting image is unavailable.</p> :
          imageError || !isBvasImage(detail.image) ? <p role="alert" className="text-rose-700">{imageError || 'The service returned an unsupported image.'} <button className={button} onClick={() => setDetailRevision((n) => n + 1)}>Retry image</button></p> :
            <img src={detail.image} alt="Supporting registered-voter document" className="max-h-[600px] max-w-full rounded-lg object-contain" onError={() => setImageError('Unable to display this image.')} />}
      </>}
    </section>}
    <dialog ref={deleteDialog} aria-labelledby="delete-voter-heading" aria-describedby="delete-voter-description"
      onCancel={(event) => { event.preventDefault(); if (!inFlight.current) setDeleting(null); }}
      onClose={() => setDeleting(null)}
      className="m-auto max-h-[90dvh] w-[calc(100%-2rem)] max-w-md overflow-y-auto rounded-2xl border border-slate-200 bg-white p-6 font-sans text-slate-900 shadow-xl backdrop:bg-slate-950/50">
      <form className="space-y-4" onSubmit={(event) => { event.preventDefault(); void remove(); }}>
        <h2 id="delete-voter-heading" className="text-lg font-semibold">Delete registered-voter record?</h2>
        <p id="delete-voter-description" className="text-sm leading-6 text-slate-600">This removes the selected record from active records. The backend retains the record and supporting image.</p>
        {deleting && <p className="break-words rounded-xl bg-slate-50 p-3 text-sm">PU: {data?.data.find((record) => record.id === deleting)?.pu_id ?? deleting}</p>}
        <div>
          <label htmlFor="delete-voter-confirmation" className="mb-2 block text-sm font-medium">Type <strong>delete</strong> to confirm</label>
          <input id="delete-voter-confirmation" className={input} value={deleteConfirmation} onChange={(event) => setDeleteConfirmation(event.target.value)}
            autoFocus autoComplete="off" autoCapitalize="none" spellCheck={false} disabled={busy} aria-describedby="delete-voter-confirmation-hint" />
          <p id="delete-voter-confirmation-hint" className="mt-2 text-xs text-slate-600">Enter the exact lowercase word to enable deletion.</p>
        </div>
        {deleteError && <p role="alert" className="text-sm text-rose-700">{deleteError}</p>}
        <div className="flex flex-wrap justify-end gap-2">
          <button className={button} type="button" disabled={busy} onClick={() => setDeleting(null)}>Cancel</button>
          <button className={`${buttonBase} border-rose-700 bg-rose-700 text-white hover:bg-rose-800`} type="submit" disabled={busy || deleteConfirmation !== 'delete'}>{busy ? 'Deleting...' : 'Delete record'}</button>
        </div>
      </form>
    </dialog>
    <section aria-labelledby="voter-records-heading" className="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
      <div className="flex flex-wrap items-center justify-between gap-2 border-b border-slate-200 px-5 py-4">
        <h2 id="voter-records-heading" className="font-semibold">Polling unit records</h2>
        <p role="status" className="text-xs text-slate-600">{loading ? 'Updating records...' : data ? `${data.meta.total.toLocaleString()} ${data.meta.total === 1 ? 'record' : 'records'}` : 'Records unavailable'}</p>
      </div>
      <div aria-busy={loading}>
      {loading ? <p role="status" className="p-6 text-sm text-slate-600">Loading registered voters...</p> : data && <table className="block w-full text-left text-xs leading-5 md:table md:table-fixed">
        <caption className="sr-only">Registered voter counts by state, LGA, ward, and polling unit</caption>
        <thead className="sr-only border-b border-slate-100 bg-slate-50 md:not-sr-only md:table-header-group"><tr>{['Location', 'Voter count', 'Note', 'Updated', 'Actions'].map((name) => <th scope="col" className={`px-4 py-2.5 text-xs font-medium text-slate-600 ${name === 'Location' ? 'w-[36%]' : name === 'Actions' ? 'w-[18%]' : ''}`} key={name}>{name}</th>)}</tr></thead>
        <tbody className="block divide-y divide-slate-200 md:table-row-group">{!data.data.length ? <tr className="block md:table-row"><td colSpan={5} className="block px-5 py-12 text-center md:table-cell"><p className="font-semibold">No registered-voter records found</p><p className="mt-2 text-slate-600">Try changing your geography filters or add a record.</p></td></tr> : data.data.map((record) => <tr className={`block md:table-row ${detailId === record.id ? 'bg-emerald-50' : 'even:bg-slate-50/60 hover:bg-slate-50'}`} key={record.id}>
          <td className="block px-4 py-3 align-middle md:table-cell">
            <div className="flex items-center gap-3">
              <span aria-hidden="true" className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-emerald-50 text-[11px] font-semibold text-emerald-800">
                {String(record.pu_id ?? 'PU').trim().slice(0, 2).toUpperCase()}
              </span>
              <dl className="min-w-0">
                <div className="flex items-baseline gap-1"><dt className="shrink-0 font-medium">PU:</dt><dd className="min-w-0 break-words font-semibold [overflow-wrap:anywhere]">{record.pu_id ?? 'Not available'}</dd></div>
                <div className="flex flex-wrap items-baseline gap-x-2 text-slate-600">
                  <div className="min-w-0"><dt className="sr-only">State</dt><dd className="break-words [overflow-wrap:anywhere]">{record.state_id ?? 'Not available'}</dd></div>
                  <div className="flex min-w-0 items-baseline gap-1"><dt className="shrink-0">LG:</dt><dd className="break-words [overflow-wrap:anywhere]">{record.lga_id ?? 'Not available'}</dd></div>
                </div>
                <div><dt className="sr-only">Ward</dt><dd className="break-words text-slate-600 [overflow-wrap:anywhere]">{record.ward_id ?? 'Not available'}</dd></div>
              </dl>
            </div>
          </td>
          <td className="block break-words px-4 py-2 align-middle md:table-cell"><span className="mr-2 text-xs text-slate-600 md:hidden">Voter count</span><span className="font-semibold tabular-nums">{record.numbers.toLocaleString()}</span></td>
          <td className="block px-4 py-2 align-middle md:table-cell"><span className="text-xs text-slate-600 md:hidden">Note</span><p className="line-clamp-2 break-words text-slate-600 [overflow-wrap:anywhere]" title={record.note || ''}>{record.note || 'No note'}</p></td>
          <td className="block break-words px-4 py-2 align-middle text-slate-600 [overflow-wrap:anywhere] md:table-cell"><span className="mr-2 text-xs md:hidden">Updated</span>{record.updated_at || 'Not available'}</td>
          <td className="block px-3 py-2 align-middle md:table-cell"><div className="flex flex-wrap gap-1">
            <button className="min-h-11 rounded-lg px-2 text-xs font-semibold text-emerald-800 hover:bg-emerald-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-700" aria-label={`View record for ${record.pu_id ?? 'unassigned polling unit'}`} onClick={() => setDetailId(record.id)}>View</button>
            {canDelete && <button className="min-h-11 rounded-lg px-2 text-xs font-medium text-rose-700 hover:bg-rose-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-rose-700 disabled:opacity-50" aria-label={`Delete record for ${record.pu_id ?? 'unassigned polling unit'}`} disabled={busy} onClick={() => setDeleting(record.id)}>Delete</button>}
          </div></td>
        </tr>)}</tbody>
      </table>}
      </div>
    </section>
    <footer className="flex flex-wrap items-center justify-between gap-4 text-slate-600">
      <label className="flex items-center gap-2 text-sm">Records per page<select className={input} value={perPage} onChange={(event) => { setPerPage(Number(event.target.value)); setPage(1); }}>{[10, 25, 50, 100].map((n) => <option key={n} value={n}>{n}</option>)}</select></label>
      {data && <div className="flex items-center gap-3 text-sm"><button className={button} disabled={loading || page <= 1} onClick={() => setPage(page - 1)}>Previous</button><span>Page {data.meta.current_page} of {data.meta.last_page} ({data.meta.total} records)</span><button className={button} disabled={loading || page >= data.meta.last_page} onClick={() => setPage(page + 1)}>Next</button></div>}
    </footer>
  </section>;
}
