import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ts } from '../../i18n/server';
import type { CrimeIncident, CrimeRecordsResponse } from '../../types';
import { isAbortError, logNonAbortError } from '../../lib/api';

function formatMonth(month: string, locale: string): string {
  const [year, m] = month.split('-').map(Number);
  if (!year || !m) return month;
  return new Date(Date.UTC(year, m - 1, 1)).toLocaleDateString(locale, {
    year: 'numeric',
    month: 'short',
    timeZone: 'UTC',
  });
}

interface CrimeRecordsSectionProps {
  /** Identity of the current selection; changing it resets the list. */
  selectionKey: string | null;
  /** Total records for the selection (from stats); the section hides when 0. */
  total?: number;
  onLoad: (offset: number) => Promise<CrimeRecordsResponse>;
}

export default function CrimeRecordsSection({
  selectionKey,
  total,
  onLoad,
}: CrimeRecordsSectionProps) {
  const { t, i18n } = useTranslation();
  const [open, setOpen] = useState(false);
  const [records, setRecords] = useState<CrimeIncident[]>([]);
  const [loadedTotal, setLoadedTotal] = useState(0);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  // Bumped whenever the selection changes; in-flight responses for a previous
  // selection are ignored when they resolve.
  const selectionIdRef = useRef(0);

  useEffect(() => {
    selectionIdRef.current += 1;
    setOpen(false);
    setRecords([]);
    setLoadedTotal(0);
    setLoading(false);
    setError(false);
  }, [selectionKey]);

  if (!total || total <= 0) return null;

  const fetchPage = async (offset: number) => {
    const myId = selectionIdRef.current;
    setLoading(true);
    setError(false);
    try {
      const data = await onLoad(offset);
      if (myId !== selectionIdRef.current) return;
      setRecords((prev) => (offset === 0 ? data.records : [...prev, ...data.records]));
      setLoadedTotal(data.total);
    } catch (err) {
      if (isAbortError(err)) return;
      logNonAbortError('Failed to fetch crime records', err);
      if (myId === selectionIdRef.current) setError(true);
    } finally {
      if (myId === selectionIdRef.current) setLoading(false);
    }
  };

  const handleToggle = () => {
    const next = !open;
    setOpen(next);
    if (next && records.length === 0 && !loading) fetchPage(0);
  };

  const shownTotal = loadedTotal || total;
  const canLoadMore = records.length < loadedTotal;

  return (
    <div className="py-1.5">
      <button
        type="button"
        onClick={handleToggle}
        className="flex w-full items-center justify-between gap-2 rounded px-1 py-1 text-left hover:bg-warm-100 dark:hover:bg-navy-800"
        aria-expanded={open}
      >
        <span className="text-[13px] font-medium text-warm-900 dark:text-warm-100">
          {open ? t('areaPane.crimeRecordsHide') : t('areaPane.crimeRecordsToggle')}
        </span>
        <span className="shrink-0 text-xs font-semibold tabular-nums text-warm-500 dark:text-warm-400">
          {t('areaPane.crimeRecordsCount', { count: shownTotal })}
        </span>
      </button>

      {open && (
        <div className="mt-1.5">
          {error ? (
            <div className="py-2 text-sm text-rose-600 dark:text-rose-400">
              {t('areaPane.crimeRecordsError')}
            </div>
          ) : records.length === 0 && loading ? (
            <div className="flex items-center gap-2 py-2 text-sm text-warm-500 dark:text-warm-400">
              <span className="h-3 w-3 animate-spin rounded-full border-2 border-teal-600 border-t-transparent dark:border-teal-400 dark:border-t-transparent" />
              {t('areaPane.crimeRecordsLoading')}
            </div>
          ) : records.length === 0 ? (
            <div className="py-2 text-sm text-warm-500 dark:text-warm-400">
              {t('areaPane.crimeRecordsEmpty')}
            </div>
          ) : (
            <>
              <ol className="divide-y divide-warm-100 dark:divide-navy-800">
                {records.map((record, index) => (
                  <li
                    key={`${record.month}-${record.lat}-${record.lon}-${index}`}
                    className="py-1.5"
                  >
                    <div className="flex items-baseline justify-between gap-2">
                      <span className="min-w-0 break-words text-[13px] font-medium text-warm-900 dark:text-warm-100">
                        {ts(record.type)}
                      </span>
                      <span className="shrink-0 text-xs tabular-nums text-warm-500 dark:text-warm-400">
                        {formatMonth(record.month, i18n.language)}
                      </span>
                    </div>
                    <div className="mt-0.5 text-xs text-warm-500 dark:text-warm-400">
                      {record.location ?? t('areaPane.crimeNoLocation')}
                    </div>
                    <div className="text-xs text-warm-400 dark:text-warm-500">
                      {record.outcome ?? t('areaPane.crimeOutcomeUnknown')}
                    </div>
                  </li>
                ))}
              </ol>
              {canLoadMore && (
                <button
                  type="button"
                  onClick={() => !loading && fetchPage(records.length)}
                  disabled={loading}
                  className="mt-2 w-full rounded border border-warm-200 px-2 py-1.5 text-xs font-medium text-warm-700 hover:bg-warm-100 disabled:opacity-50 dark:border-navy-700 dark:text-warm-200 dark:hover:bg-navy-800"
                >
                  {loading ? t('areaPane.crimeRecordsLoading') : t('areaPane.crimeRecordsLoadMore')}
                </button>
              )}
            </>
          )}
        </div>
      )}
    </div>
  );
}
