'use client';

import { FormEvent, useEffect, useRef, useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { IncidentPage, IncidentRecord, isIncidentPage, isIncidentRecord, validateIncidentFields } from '@/lib/incidentReports';
import { isRecord } from '@/lib/users';
import { isBvasImage } from '@/lib/bvasInfo';
import { MAX_VOTER_IMAGE_SIZE } from '@/lib/registeredVoters';
import { EMPTY_GEOGRAPHY, GeographySelection, geographyFilterQuery } from '@/lib/geography';
import { GeographyFields, GeographyFilterCards } from './GeographyFields';
import { BvasReportDetailsModal, BvasReportDeleteDialog, BvasReportTable, reportButton as button, reportInput as input } from './BvasReportPresentation';

const primaryButton = 'min-h-11 rounded-xl bg-emerald-700 px-4 py-2 text-sm font-semibold text-white hover:bg-emerald-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-700 focus-visible:ring-offset-2 disabled:opacity-50';
const field = `${input} w-full`;
function message(error: unknown) { return error instanceof Error ? error.message : 'Unable to reach the incidents 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');
    throw new Error('Your session has expired. Sign in again.');
  }
  if (response.status === 204 && options.method === 'DELETE') return null;
  let data: unknown;
  try { data = await response.json(); }
  catch { throw new Error('The incidents service returned an invalid response. Please retry.'); }
  if (!response.ok) {
    const errors = isRecord(data) && isRecord(data.errors) ? Object.entries(data.errors).flatMap(([key, values]) =>
      Array.isArray(values) ? values.filter((value): value is string => typeof value === 'string').map((value) => `${key}: ${value}`) : []) : [];
    throw new Error(errors.length ? errors.join(' ') : isRecord(data) && typeof data.error === 'string' ? data.error : 'The incident request failed.');
  }
  return data;
}

export function IncidentReports(props: { canDelete: boolean; canFilterGeography: boolean }) {
  const [client] = useState(() => new QueryClient());
  return <QueryClientProvider client={client}><IncidentContent {...props} /></QueryClientProvider>;
}

function IncidentContent({ canDelete, canFilterGeography }: { canDelete: boolean; canFilterGeography: boolean }) {
  const [geography, setGeography] = useState<GeographySelection>({ ...EMPTY_GEOGRAPHY });
  const [status, setStatus] = useState('');
  const [page, setPage] = useState(1);
  const [perPage, setPerPage] = useState(25);
  const [revision, setRevision] = useState(0);
  const [data, setData] = useState<IncidentPage | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [notice, setNotice] = useState('');
  const [detailId, setDetailId] = useState<string | null>(null);
  const [detail, setDetail] = useState<IncidentRecord | null>(null);
  const [detailError, setDetailError] = useState('');
  const [detailRevision, setDetailRevision] = useState(0);
  const [imageFailed, setImageFailed] = useState(false);
  const [creating, setCreating] = useState(false);
  const [createGeography, setCreateGeography] = useState<GeographySelection>({ ...EMPTY_GEOGRAPHY });
  const [puId, setPuId] = useState('');
  const [formError, setFormError] = useState('');
  const [deleting, setDeleting] = useState<IncidentRecord | null>(null);
  const [deleteError, setDeleteError] = useState('');
  const [treating, setTreating] = useState<IncidentRecord | null>(null);
  const [treatError, setTreatError] = useState('');
  const [busy, setBusy] = useState(false);
  const inFlight = useRef(false);

  useEffect(() => {
    const controller = new AbortController();
    setLoading(true); setData(null); setError('');
    const query = canFilterGeography ? geographyFilterQuery(geography) : new URLSearchParams();
    query.set('page', String(page)); query.set('per_page', String(perPage));
    if (status !== '') query.set('status', status);
    request(`/api/incident-reports?${query}`, { signal: controller.signal })
      .then((value) => {
        if (!isIncidentPage(value)) throw new Error('The incidents service returned invalid records.');
        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();
  }, [geography, status, page, perPage, revision, canFilterGeography]);

  useEffect(() => {
    setDetail(null); setDetailError(''); setImageFailed(false);
    if (!detailId) return;
    const controller = new AbortController();
    request(`/api/incident-reports/${encodeURIComponent(detailId)}`, { signal: controller.signal })
      .then((value) => {
        if (!isRecord(value) || !isIncidentRecord(value.data)) throw new Error('The incidents 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 refreshAfterRemoval = () => {
    if (page > 1 && data?.data.length === 1) setPage(page - 1);
    else setRevision((value) => value + 1);
  };

  const create = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (inFlight.current) return;
    const body = new FormData(event.currentTarget);
    const localTime = String(body.get('occurred_at'));
    body.set('occurred_at', `${localTime.replace('T', ' ')}${localTime.length === 16 ? ':00' : ''}`);
    body.set('pu_id', puId);
    const errors = validateIncidentFields(Object.fromEntries(body));
    const image = body.get('image');
    if (image instanceof File && image.size === 0) body.delete('image');
    else if (!(image instanceof File) || image.size > MAX_VOTER_IMAGE_SIZE || !['image/jpeg', 'image/png', 'image/webp'].includes(image.type)) errors.image = ['Choose a JPEG, PNG, or WebP image of at most 5120 KB.'];
    if (Object.keys(errors).length) { setFormError(Object.values(errors).flat().join(' ')); return; }
    inFlight.current = true; setBusy(true); setFormError(''); setNotice('');
    try {
      const value = await request('/api/incident-reports', { method: 'POST', body });
      if (!isRecord(value) || !isIncidentRecord(value.data)) throw new Error('The incidents service did not confirm creation.');
      setCreating(false); setPage(1); setRevision((value) => value + 1);
      setNotice('Incident created as untreated.');
    } catch (error) { setFormError(message(error)); }
    finally { inFlight.current = false; setBusy(false); }
  };

  const remove = async (confirmation: string) => {
    if (!canDelete || !deleting || confirmation !== 'delete' || inFlight.current) return;
    inFlight.current = true; setBusy(true); setDeleteError(''); setNotice('');
    try {
      await request(`/api/incident-reports/${encodeURIComponent(deleting.id)}`, { method: 'DELETE' });
      if (detailId === deleting.id) setDetailId(null);
      setDeleting(null); refreshAfterRemoval();
      setNotice('Incident removed from active records. Its record and image are retained.');
    } catch (error) { setDeleteError(message(error)); }
    finally { inFlight.current = false; setBusy(false); }
  };

  const markTreated = async () => {
    if (!treating || treating.status === 1 || inFlight.current) return;
    inFlight.current = true; setBusy(true); setTreatError(''); setNotice('');
    try {
      const value = await request(`/api/incident-reports/${encodeURIComponent(treating.id)}`, {
        method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 1 }),
      });
      if (!isRecord(value) || !isIncidentRecord(value.data) || value.data.status !== 1) throw new Error('The incidents service did not confirm treatment.');
      setTreating(null); refreshAfterRemoval();
      setNotice('Incident marked treated.');
    } catch (error) { setTreatError(message(error)); }
    finally { inFlight.current = false; setBusy(false); }
  };

  return <section className="space-y-6 font-sans text-slate-900" aria-labelledby="incidents-heading">
    <header className="flex flex-wrap items-center justify-between gap-3">
      <div><h1 id="incidents-heading" className="text-2xl font-bold">Incidents</h1><p className="mt-1 text-sm text-slate-600">Report and track incidents within your assigned geography.</p></div>
      <div className="flex gap-2"><button className={button} disabled={loading || busy} onClick={() => setRevision((value) => value + 1)}>Refresh</button><button className={primaryButton} disabled={busy} onClick={() => {
        setCreating(true); setFormError(''); setCreateGeography({ ...EMPTY_GEOGRAPHY }); setPuId('');
      }}>Report incident</button></div>
    </header>
    {canFilterGeography && <GeographyFilterCards subject="incidents" value={geography} onChange={(next) => { setGeography(next); setPage(1); }} />}
    <label className="flex flex-wrap items-center gap-2 text-sm">Status<select className={input} value={status} onChange={(event) => { setStatus(event.target.value); setPage(1); }}>
      <option value="">All incidents</option><option value="0">Untreated</option><option value="1">Treated</option>
    </select></label>
    {notice && <p role="status" className="rounded-xl bg-emerald-50 p-3 text-sm text-emerald-900">{notice}</p>}
    {error && <p role="alert" className="text-sm text-rose-700">{error} <button className={button} onClick={() => setRevision((value) => value + 1)}>Retry list</button></p>}
    <BvasReportTable title="Incident records" data={data?.data} total={data?.meta.total} loading={loading} selectedId={detailId} canDelete={canDelete} busy={busy} onView={setDetailId} onDelete={(record) => { setDeleting(record); setDeleteError(''); }}
      columns={[
        { label: 'Incident', render: (record) => <p className="font-medium text-slate-900">{record.title}</p> },
        { label: 'Status', render: (record) => <span className={`rounded-full px-2 py-1 font-medium ${record.status ? 'bg-emerald-50 text-emerald-800' : 'bg-amber-50 text-amber-800'}`}>{record.status ? 'Treated' : 'Untreated'}</span> },
        { label: 'Occurred', render: (record) => record.occurred_at },
      ]} />
    <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((value) => <option key={value}>{value}</option>)}</select></label>
      {data && <div className="flex flex-wrap items-center gap-3"><button className={button} disabled={loading || page <= 1} onClick={() => setPage(page - 1)}>Previous</button><span>Page {data.meta.current_page} of {data.meta.last_page}</span><button className={button} disabled={loading || page >= data.meta.last_page} onClick={() => setPage(page + 1)}>Next</button></div>}
    </footer>
    {creating && <BvasReportDetailsModal title="Report incident" onClose={() => { if (!inFlight.current) setCreating(false); }}>
      <form onSubmit={create} className="space-y-4">
        {formError && <p role="alert" className="text-sm text-rose-700">{formError}</p>}
        <fieldset disabled={busy} className="space-y-4">
          <label className="block text-sm font-medium">Title<input className={`${field} mt-1`} name="title" maxLength={255} required /></label>
          <label className="block text-sm font-medium">Description<textarea className={`${field} mt-1`} name="description" rows={4} maxLength={5000} required /></label>
          <label className="block text-sm font-medium">Occurred at<input className={`${field} mt-1`} name="occurred_at" type="datetime-local" step="1" required /><span className="mt-1 block text-xs font-normal text-slate-600">Enter the incident's local date and time.</span></label>
          <div><h3 className="mb-2 text-sm font-semibold">Polling unit</h3><GeographyFields value={createGeography} onChange={(next) => { setCreateGeography(next); setPuId(next.polling_unit_id); }} />
            <label className="mt-3 block text-sm">Polling unit UUID<input className={`${field} mt-1`} value={puId} onChange={(event) => setPuId(event.target.value)} required placeholder="Select above or enter an assigned polling unit UUID" /></label>
            <p className="mt-1 text-xs text-slate-600">Only polling units within your assigned geography are allowed. Parent geography is derived by the service.</p>
          </div>
          <label className="block text-sm font-medium">Supporting image (optional)<input className={`${field} mt-1`} name="image" type="file" accept="image/jpeg,image/png,image/webp" /><span className="mt-1 block text-xs font-normal text-slate-600">JPEG, PNG, or WebP. Maximum 5120 KB.</span></label>
          <div className="flex justify-end gap-2"><button type="button" className={button} onClick={() => setCreating(false)}>Cancel</button><button className={primaryButton} type="submit">{busy ? 'Saving...' : 'Create incident'}</button></div>
        </fieldset>
      </form>
    </BvasReportDetailsModal>}
    {detailId && <BvasReportDetailsModal title="Incident details" onClose={() => setDetailId(null)}>
      {detailError ? <p role="alert" className="text-sm text-rose-700">{detailError} <button className={button} onClick={() => setDetailRevision((value) => value + 1)}>Retry details</button></p> : !detail ? <p role="status">Loading incident...</p> : <>
        <h3 className="text-lg font-semibold">{detail.title}</h3>
        <p className="whitespace-pre-wrap break-words text-sm">{detail.description}</p>
        <dl className="grid gap-3 text-sm sm:grid-cols-2">
          {[['State', detail.state_id], ['LGA', detail.lga_id], ['Ward', detail.ward_id], ['Polling unit', detail.pu_id], ['Occurred at', detail.occurred_at], ['Updated', detail.updated_at], ['Status', detail.status ? 'Treated' : 'Untreated']].map(([label, value]) => <div key={label}><dt className="text-xs text-slate-600">{label}</dt><dd className="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-sm text-rose-700">Unable to display the supporting image. <button className={button} onClick={() => setDetailRevision((value) => value + 1)}>Retry image</button></p> :
          <img src={detail.image} alt="Supporting incident evidence" className="max-h-[500px] max-w-full rounded-xl object-contain" onError={() => setImageFailed(true)} />}
        {detail.status === 0 && <div className="space-y-2"><p className="text-xs text-slate-600">Only the creator or a Super Admin can mark this incident treated within their current scope.</p><button className={primaryButton} disabled={busy} onClick={() => { setTreating(detail); setTreatError(''); setDetailId(null); }}>Mark treated</button></div>}
      </>}
    </BvasReportDetailsModal>}
    {treating && <BvasReportDetailsModal title="Mark incident treated?" onClose={() => { if (!inFlight.current) setTreating(null); }}>
      <p className="break-words font-semibold">{treating.title}</p><p className="text-sm text-slate-600">This incident cannot be reopened after treatment. Only the creator or a Super Admin may confirm.</p>
      {treatError && <p role="alert" className="text-sm text-rose-700">{treatError}</p>}
      <div className="flex justify-end gap-2"><button className={button} disabled={busy} onClick={() => setTreating(null)}>Cancel</button><button className={primaryButton} disabled={busy} onClick={() => void markTreated()}>{busy ? 'Updating...' : 'Mark treated'}</button></div>
    </BvasReportDetailsModal>}
    {canDelete && deleting && <BvasReportDeleteDialog key={deleting.id} report={deleting} title="incident" prerequisite="No restore or permanent-delete API is available." confirmLabel="Delete incident" busy={busy} error={deleteError} onCancel={() => setDeleting(null)} onConfirm={remove} />}
  </section>;
}
