import { useCallback, useEffect, useRef, useState } from 'react';
import { api, type Inbox, type InboxRow, type InboxStatus, type SyncResult } from '../api.js';
import { formatDayTimeParts, formatRelative } from '../components.js';

const INPUT = 'rounded border border-gray-300 px-2 py-1.5 text-sm';

const STATUS_TONE: Record<InboxStatus, string> = {
  pending: 'border-amber-300 bg-amber-50 text-amber-800',
  signed: 'border-green-300 bg-green-50 text-green-800',
  declined: 'border-red-300 bg-red-50 text-red-800',
};

const isoDaysAgo = (days: number) =>
  new Date(Date.now() - days * 86_400_000).toISOString().slice(0, 10);

/**
 * Date and time as two nowrap spans: they sit on one line when the column
 * allows it, otherwise the time wraps under the date. The time matters —
 * Dropbox orders to the second, and same-day rows are common.
 */
function DateTime({ iso }: { iso: string }) {
  const { day, time } = formatDayTimeParts(iso);
  return (
    <>
      <span className="whitespace-nowrap">{day}</span>{' '}
      <span className="whitespace-nowrap text-gray-400">{time}</span>
    </>
  );
}

export default function NdaInbox({
  onOpenBuyer,
  onChanged,
}: {
  onOpenBuyer: (buyerId: string) => void;
  /** Imported rounds land in Today's pending list, so the badge follows. */
  onChanged: () => void;
}) {
  const [since, setSince] = useState(() => isoDaysAgo(90));
  const [inbox, setInbox] = useState<Inbox | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
  const [syncing, setSyncing] = useState(false);
  const [syncResult, setSyncResult] = useState<SyncResult | null>(null);
  // Business chosen per row; '' means "import the NDA without a deal".
  const [picked, setPicked] = useState<Record<string, string>>({});
  const [busy, setBusy] = useState<string | null>(null);
  const [notice, setNotice] = useState<string | null>(null);
  const poll = useRef<number | null>(null);

  const rows: InboxRow[] | null = inbox?.requests ?? null;
  const refreshing = inbox?.refresh_state === 'running';
  const refreshError = inbox?.refresh_state?.startsWith('error:')
    ? inbox.refresh_state.slice('error:'.length)
    : null;

  /** Reads the mirror out of the database — this never talks to Dropbox. */
  const load = useCallback(async () => {
    setLoading(true);
    try {
      const res = await api.ndaInbox(since);
      setInbox(res);
      setError(null);
      // Preselect the best suggestion, but never overwrite a manual choice.
      setPicked((current) => {
        const next = { ...current };
        for (const row of res.requests) {
          if (next[row.signature_request_id] === undefined) {
            next[row.signature_request_id] = row.business_suggestions[0]?.id ?? '';
          }
        }
        return next;
      });
      return res;
    } catch (err) {
      setError((err as Error).message);
      return null;
    } finally {
      setLoading(false);
    }
  }, [since]);

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

  // Whenever a walk is in flight — started here or elsewhere — watch it until
  // it finishes, then show whatever it brought in.
  useEffect(() => {
    if (!refreshing) {
      if (poll.current !== null) {
        window.clearInterval(poll.current);
        poll.current = null;
      }
      return;
    }
    if (poll.current !== null) return;
    poll.current = window.setInterval(() => void load(), 3000);
    return () => {
      if (poll.current !== null) {
        window.clearInterval(poll.current);
        poll.current = null;
      }
    };
  }, [refreshing, load]);

  async function refresh() {
    setError(null);
    try {
      await api.refreshInbox(since);
      // Flip to "running" at once so the poller starts without a round trip.
      setInbox((current) => (current ? { ...current, refresh_state: 'running' } : current));
    } catch (err) {
      setError((err as Error).message);
    }
  }

  async function sync() {
    setSyncing(true);
    setSyncResult(null);
    setError(null);
    try {
      setSyncResult(await api.syncInbox());
      await load();
      onChanged();
    } catch (err) {
      setError((err as Error).message);
    } finally {
      setSyncing(false);
    }
  }

  async function importRow(row: InboxRow) {
    setBusy(row.signature_request_id);
    setNotice(null);
    setError(null);
    try {
      const res = await api.importInbox(
        row.signature_request_id,
        row.known_buyer?.buyer_id,
        picked[row.signature_request_id] || undefined,
      );
      setNotice(
        res.warning ??
          `Imported ${row.signer.name || row.signer.email}` +
            `${res.created.buyer ? ' as a new buyer' : ' into the existing buyer'}` +
            `${res.nas_path ? ' · PDF filed' : ''}.`,
      );
      await load();
      onChanged();
    } catch (err) {
      setError((err as Error).message);
    } finally {
      setBusy(null);
    }
  }

  return (
    <div>
      <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
        <div className="flex items-center gap-3">
          <label className="flex items-center gap-2 text-sm text-gray-600">
            Since
            <input
              type="date"
              value={since}
              onChange={(e) => setSince(e.target.value)}
              className={INPUT}
            />
          </label>
          <span className="text-sm text-gray-500">
            Last refreshed: {formatRelative(inbox?.last_refresh_at ?? null)}
            {loading && !refreshing && ' · loading…'}
          </span>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={refresh}
            disabled={refreshing}
            title="Fetches the signature requests from Dropbox Sign in the background"
            className="rounded border border-gray-300 bg-white px-3 py-1.5 text-sm hover:bg-gray-100 disabled:opacity-50"
          >
            {refreshing ? 'Refreshing…' : 'Refresh'}
          </button>
          <button
            onClick={sync}
            disabled={syncing}
            className="rounded bg-gray-900 px-3 py-1.5 text-sm text-white disabled:opacity-50"
          >
            {syncing ? 'Syncing…' : 'Sync signatures'}
          </button>
        </div>
      </div>

      {refreshing && (
        <p className="mb-3 text-sm text-gray-600">
          Fetching from Dropbox Sign in the background — the table below stays usable.
        </p>
      )}
      {refreshError && (
        <p className="mb-3 text-sm text-red-600">Last refresh failed: {refreshError}</p>
      )}

      {syncResult && (
        <p className="mb-3 text-sm text-gray-600">
          Checked {syncResult.checked} · newly signed {syncResult.signed} · declined{' '}
          {syncResult.declined} · failed {syncResult.failed}
          {syncResult.warnings.length > 0 && (
            <span className="text-amber-700"> · {syncResult.warnings.join('; ')}</span>
          )}
        </p>
      )}
      {notice && <p className="mb-3 text-sm text-gray-600">{notice}</p>}
      {error && <p className="mb-3 text-sm text-red-600">{error}</p>}

      <table className="w-full border-collapse bg-white text-sm">
        <thead>
          <tr className="border-b border-gray-200 text-left text-xs uppercase tracking-wide text-gray-500">
            <th className="w-28 px-3 py-2 font-medium">Date</th>
            <th className="px-3 py-2 font-medium">Signer</th>
            <th className="px-3 py-2 font-medium">E-mail</th>
            <th className="w-24 px-3 py-2 font-medium">Status</th>
            <th className="px-3 py-2 font-medium">Title</th>
            <th className="px-3 py-2 font-medium">Buyer</th>
            <th className="px-3 py-2 font-medium">Deal</th>
            <th className="w-24 px-3 py-2 font-medium" />
          </tr>
        </thead>
        <tbody>
          {rows?.map((row) => (
            <tr key={row.signature_request_id} className="border-b border-gray-100 align-top">
              <td className="px-3 py-1.5 text-gray-500">
                <DateTime iso={row.created_at} />
              </td>
              <td className="px-3 py-1.5">{row.signer.name || '—'}</td>
              <td className="px-3 py-1.5 text-gray-600">{row.signer.email || '—'}</td>
              <td className="px-3 py-1.5">
                <span
                  className={`rounded-full border px-2 py-0.5 text-xs whitespace-nowrap ${
                    STATUS_TONE[row.status]
                  }`}
                >
                  {row.status}
                </span>
              </td>
              <td className="px-3 py-1.5 text-gray-600">{row.title_remainder || '—'}</td>
              <td className="px-3 py-1.5">
                {row.known_buyer ? (
                  <button
                    onClick={() => row.known_buyer && onOpenBuyer(row.known_buyer.buyer_id)}
                    className="rounded-full border border-blue-300 bg-blue-50 px-2 py-0.5 text-xs text-blue-800"
                  >
                    Known: {row.known_buyer.company_name ?? row.known_buyer.contact_name}
                  </button>
                ) : (
                  <span className="text-xs text-gray-400">new</span>
                )}
              </td>
              <td className="px-3 py-1.5">
                {row.imported ? (
                  <span className="text-xs text-gray-400">—</span>
                ) : (
                  <select
                    value={picked[row.signature_request_id] ?? ''}
                    onChange={(e) =>
                      setPicked({ ...picked, [row.signature_request_id]: e.target.value })
                    }
                    className="w-56 rounded border border-gray-300 px-1.5 py-1 text-sm"
                  >
                    <option value="">— no deal —</option>
                    {row.business_suggestions.map((business) => (
                      <option key={business.id} value={business.id}>
                        {business.name}
                      </option>
                    ))}
                  </select>
                )}
              </td>
              <td className="px-3 py-1.5">
                {row.imported ? (
                  <button
                    onClick={() => row.imported && onOpenBuyer(row.imported.buyer_id)}
                    className="text-sm text-green-700 hover:underline"
                    title="Already imported — open the buyer"
                  >
                    ✓ imported
                  </button>
                ) : (
                  <button
                    onClick={() => importRow(row)}
                    disabled={busy === row.signature_request_id}
                    className="rounded bg-gray-900 px-2 py-1 text-xs text-white disabled:opacity-50"
                  >
                    {busy === row.signature_request_id ? 'Importing…' : 'Import'}
                  </button>
                )}
              </td>
            </tr>
          ))}
          {rows && rows.length === 0 && (
            <tr>
              <td colSpan={8} className="px-3 py-4 text-gray-500">
                {inbox?.last_refresh_at
                  ? 'No NDA signature requests in this period.'
                  : 'Nothing fetched yet — press Refresh to load the signature requests.'}
              </td>
            </tr>
          )}
        </tbody>
      </table>
    </div>
  );
}
