'use client';

import { FormEvent, useEffect, useRef, useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BvasInfo, BvasInfoPage, isBvasImage, isBvasInfo, isBvasInfoPage, validateBvasQuery } from '@/lib/bvasInfo';
import { EMPTY_GEOGRAPHY, GeographySelection, geographyFilterQuery } from '@/lib/geography';
import { isRecord } from '@/lib/users';
import { GeographyFilterCards } from './GeographyFields';
import { MAX_VOTER_IMAGE_SIZE } from '@/lib/registeredVoters';

const button = 'inline-flex min-h-11 items-center justify-center rounded-lg border border-slate-300 px-4 py-2 text-sm font-semibold hover:bg-slate-100 disabled:opacity-50';
const input = 'min-h-11 rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm';
function message(error: unknown) { return error instanceof Error ? error.message : 'Unable to reach the BVAS service.'; }
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 errors = 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(errors.length ? errors.join(' ') : isRecord(data) && typeof data.error === 'string' ? data.error : 'The BVAS request failed.');
  }
  return data;
}

export function BvasInformation(props: { canCreate?: boolean; canDelete: boolean; canFilterGeography: boolean }) {
  const [client] = useState(() => new QueryClient());
  return <QueryClientProvider client={client}><BvasContent {...props} /></QueryClientProvider>;
}

function BvasContent({ canCreate = false, canDelete, canFilterGeography }: { canCreate?: boolean; canDelete: boolean; canFilterGeography: boolean }) {
  const [creating, setCreating] = useState(false);
  const [createError, setCreateError] = useState('');
  const [geography, setGeography] = useState<GeographySelection>({ ...EMPTY_GEOGRAPHY });
  const [filters, setFilters] = useState('');
  const [page, setPage] = useState(1);
  const [perPage, setPerPage] = useState(25);
  const [revision, setRevision] = useState(0);
  const [data, setData] = useState<BvasInfoPage | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [filterError, setFilterError] = useState('');
  const [detailId, setDetailId] = useState<string | null>(null);
  const [detail, setDetail] = useState<BvasInfo | null>(null);
  const [detailError, setDetailError] = useState('');
  const [detailRevision, setDetailRevision] = useState(0);
  const [imageFailed, setImageFailed] = useState(false);
  const [deleting, setDeleting] = useState<BvasInfo | null>(null);
  const [busy, setBusy] = useState(false);
  const inFlight = useRef(false);
  const [deleteError, setDeleteError] = useState('');
  const [notice, setNotice] = useState('');

  useEffect(() => {
    const controller = new AbortController();
    setLoading(true); setError(''); setData(null);
    request(`/api/bvas-info?${filters}${filters ? '&' : ''}page=${page}&per_page=${perPage}`, { signal: controller.signal })
      .then((value) => {
        if (!isBvasInfoPage(value)) throw new Error('The BVAS service returned an invalid list.');
        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();
  }, [filters, page, perPage, revision]);

  useEffect(() => {
    setDetail(null); setDetailError(''); setImageFailed(false);
    if (!detailId) return;
    const controller = new AbortController();
    request(`/api/bvas-info/${encodeURIComponent(detailId)}`, { signal: controller.signal })
      .then((value) => {
        if (!isRecord(value) || !isBvasInfo(value.data)) throw new Error('The BVAS service returned invalid details.');
        if (!controller.signal.aborted) setDetail(value.data);
      }).catch((error) => { if (!controller.signal.aborted) setDetailError(message(error)); });
    return () => controller.abort();
  }, [detailId, detailRevision]);

  const remove = async () => {
    if (!deleting || inFlight.current) return;
    inFlight.current = true; setBusy(true); setDeleteError('');
    try {
      await request(`/api/bvas-info/${encodeURIComponent(deleting.id)}`, { method: 'DELETE' });
      if (detailId === deleting.id) setDetailId(null);
      setDeleting(null); setNotice('BVAS submission removed from active records. The backend retains the record and image.');
      if (page > 1 && data?.data.length === 1) setPage(page - 1);
      else setRevision((n) => n + 1);
    } catch (error) { setDeleteError(message(error)); }
    finally { inFlight.current = false; setBusy(false); }
  };

  const create = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (!canCreate || 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) {
      setCreateError('Choose an image of at most 5120 KB.'); return;
    }
    inFlight.current = true; setBusy(true); setCreateError(''); setNotice('');
    try {
      await request('/api/bvas-info', { method: 'POST', body });
      form.reset(); setCreating(false); setPage(1); setRevision((n) => n + 1);
      setNotice('BVAS information created. The list reflects your current filters.');
    } catch (error) { setCreateError(message(error)); }
    finally { inFlight.current = false; setBusy(false); }
  };

  return <section aria-labelledby="bvas-heading" className="space-y-5">
    {canFilterGeography && <GeographyFilterCards subject="BVAS" value={geography} onChange={(next) => {
      setGeography(next);
      const query = geographyFilterQuery(next);
      const errors = validateBvasQuery(query, true);
      setFilterError(Object.values(errors).flat().join(' '));
      if (Object.keys(errors).length) return;
      setFilters(query.toString()); setPage(1); setRevision((n) => n + 1);
    }} />}
    <header className="flex flex-wrap items-center justify-between gap-3">
      <div><h1 id="bvas-heading" className="text-2xl font-bold">BVAS information</h1><p className="mt-1 text-sm text-slate-600">Active submissions within your assigned geography.</p></div>
      <div className="flex gap-2">
        <button className={button} disabled={loading || busy} onClick={() => setRevision((n) => n + 1)}>Refresh</button>
        {canCreate && <button className={button} disabled={busy} aria-expanded={creating} aria-controls="bvas-create-form" onClick={() => { setCreating(true); setCreateError(''); }}>Create BVAS info</button>}
      </div>
    </header>
    {notice && <p role="status" className="rounded-lg bg-emerald-50 p-3 text-emerald-900">{notice}</p>}
    {canCreate && creating && <form id="bvas-create-form" onSubmit={create} className="space-y-4 rounded-xl border bg-white p-5" aria-labelledby="bvas-create-heading">
      <h2 id="bvas-create-heading" className="text-lg font-bold">Create BVAS information</h2>
      {createError && <p role="alert" className="text-rose-700">{createError}</p>}
      <fieldset disabled={busy} className="space-y-4">
        <div className="grid gap-4 sm:grid-cols-2">
          <div><label htmlFor="bvas-time" className="mb-1 block text-sm font-semibold">Time</label><input id="bvas-time" name="time" type="time" required className={`${input} w-full`} /></div>
          <div><label htmlFor="bvas-device" className="mb-1 block text-sm font-semibold">Device ID</label><input id="bvas-device" name="device_id" required maxLength={255} className={`${input} w-full`} /></div>
          {(['po', 'apo1', 'apo2', 'apo3'] as const).map((field) => <div key={field}>
            <label htmlFor={`bvas-${field}`} className="mb-1 block text-sm font-semibold">{field.toUpperCase()}</label>
            <select id={`bvas-${field}`} name={field} required defaultValue="" className={`${input} w-full`}>
              <option value="" disabled>Select Yes or No</option><option value="1">Yes</option><option value="0">No</option>
            </select>
          </div>)}
        </div>
        <div><label htmlFor="bvas-note" className="mb-1 block text-sm font-semibold">Note (optional)</label><textarea id="bvas-note" name="note" rows={3} maxLength={5000} className={`${input} w-full`} /></div>
        <div><label htmlFor="bvas-image" className="mb-1 block text-sm font-semibold">Supporting image</label><input id="bvas-image" name="image" type="file" accept="image/jpeg,image/png,image/gif,image/webp" required className={`${input} w-full`} /><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 type="submit" className={button}>{busy ? 'Saving...' : 'Save BVAS info'}</button><button type="button" className={button} onClick={() => setCreating(false)}>Cancel</button></div>
      </fieldset>
    </form>}
    {filterError && <p role="alert" className="text-sm text-rose-700">{filterError}</p>}
    {deleting && <section role="alertdialog" aria-labelledby="bvas-delete-heading" aria-describedby="bvas-delete-description" className="space-y-3 rounded-xl border border-rose-200 bg-rose-50 p-4">
      <h2 id="bvas-delete-heading" className="font-bold">Remove this active BVAS submission?</h2>
      <p id="bvas-delete-description">Device: {deleting.device_id}. This soft-deletes the submission. Its record and image are retained, and a replacement may then be submitted.</p>
      {deleteError && <p role="alert" className="text-rose-700">{deleteError}</p>}
      <div className="flex gap-2"><button className={button} disabled={busy} onClick={() => void remove()}>{busy ? 'Removing...' : 'Remove submission'}</button><button className={button} disabled={busy} onClick={() => setDeleting(null)}>Cancel</button></div>
    </section>}
    {detailId && <section aria-label="BVAS submission details" className="space-y-4 rounded-xl border bg-white p-4">
      <div className="flex justify-between gap-3"><h2 className="text-lg font-bold">BVAS submission 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 details...</p> : <>
        <dl className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          {[
            ['Geozone', detail.geozone_id], ['State', detail.state_id], ['LGA', detail.lga_id], ['Ward', detail.ward_id], ['Polling unit', detail.pu_id],
            ['Time', detail.time], ['Device ID', detail.device_id], ['PO', detail.po ? 'Yes' : 'No'],
            ['APO 1', detail.apo1 ? 'Yes' : 'No'], ['APO 2', detail.apo2 ? 'Yes' : 'No'], ['APO 3', detail.apo3 ? 'Yes' : 'No'],
            ['Note', detail.note || 'No note'], ['Updated', detail.updated_at],
          ].map(([label, value]) => <div key={label}><dt className="text-sm text-slate-600">{label}</dt><dd className="whitespace-pre-wrap break-words font-medium">{value || 'Not available'}</dd></div>)}
        </dl>
        {!detail.image ? <p className="text-sm text-slate-600">Supporting image is unavailable.</p> :
          imageFailed || !isBvasImage(detail.image) ? <p role="alert" className="text-rose-700">Unable to display the supporting image. <button className={button} onClick={() => setDetailRevision((n) => n + 1)}>Reload details</button></p> :
            <img src={detail.image} alt="Supporting BVAS submission document" className="max-h-[600px] max-w-full rounded-lg object-contain" onError={() => setImageFailed(true)} />}
      </>}
    </section>}
    {error && <p role="alert" className="text-rose-700">{error} <button className={button} onClick={() => setRevision((n) => n + 1)}>Retry list</button></p>}
    <div aria-busy={loading} className="overflow-x-auto rounded-xl border bg-white">
      {loading ? <p role="status" className="p-5">Loading BVAS information...</p> : data && <table className="w-full text-left text-sm">
        <thead className="bg-slate-100"><tr>{['Device', 'State', 'LGA', 'Ward', 'Polling unit', 'Time', 'Actions'].map((name) => <th scope="col" className="p-3" key={name}>{name}</th>)}</tr></thead>
        <tbody>{!data.data.length ? <tr><td colSpan={7} className="p-5 text-center text-slate-600">No active BVAS submissions found.</td></tr> : data.data.map((record) => <tr key={record.id} className="border-t">
          {[record.device_id, record.state_id, record.lga_id, record.ward_id, record.pu_id, record.time].map((value, index) => <td key={index} className="p-3">{value || 'Not available'}</td>)}
          <td className="p-3"><div className="flex gap-2"><button className={button} onClick={() => setDetailId(record.id)}>View</button>{canDelete && <button className={button} disabled={busy} onClick={() => { setDeleting(record); setDeleteError(''); }}>Delete</button>}</div></td>
        </tr>)}</tbody>
      </table>}
    </div>
    <footer className="flex flex-wrap items-center justify-between gap-3 text-sm">
      <label className="flex items-center gap-2">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"><button className={button} disabled={page <= 1 || loading} 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={page >= data.meta.last_page || loading} onClick={() => setPage(page + 1)}>Next</button></div>}
    </footer>
  </section>;
}
