'use client';

import { useState, useEffect, useCallback } from 'react';

type LoginCategory = 'browser' | 'token' | 'external';

type RefreshHint =
  | { kind: 'open-url'; url: string; description?: string }
  | { kind: 'show-command'; command: string; description: string }
  | { kind: 'open-settings'; section: string };

interface LoginSource {
  id: string;
  label: string;
  category: LoginCategory;
  detail?: string;
  refresh: RefreshHint;
}

interface LoginCheckResult {
  ok: boolean;
  message?: string;
  landed_url?: string;
  checked_at: number;
  duration_ms: number;
}

interface Row {
  source: LoginSource;
  result: LoginCheckResult | null;
}

const CATEGORY_LABEL: Record<LoginCategory, string> = {
  browser: 'Browser Sessions',
  token: 'API Tokens',
  external: 'External Auth',
};

function timeAgo(ts: number): string {
  const s = Math.round((Date.now() - ts) / 1000);
  if (s < 60) return `${s}s ago`;
  if (s < 3600) return `${Math.round(s / 60)}m ago`;
  if (s < 86400) return `${Math.round(s / 3600)}h ago`;
  return `${Math.round(s / 86400)}d ago`;
}

export default function LoginStatusPanel({ onClose }: { onClose: () => void }) {
  const [rows, setRows] = useState<Row[] | null>(null);
  const [busyAll, setBusyAll] = useState(false);
  const [busyIds, setBusyIds] = useState<Set<string>>(new Set());
  const [showCmd, setShowCmd] = useState<{ command: string; description: string } | null>(null);

  const loadCached = useCallback(() => {
    fetch('/api/login-status')
      .then((r) => r.json())
      .then((j) => setRows(j.rows || []))
      .catch(() => {});
  }, []);

  // On mount: force a fresh probe (POST) so the panel never shows a stale
  // cached 401 after the user fixed the token in another tab. After that,
  // poll the cache (GET) every 5s — refresh-via-curl actions update the
  // cache and we pick them up without re-probing every poll cycle.
  useEffect(() => {
    (async () => {
      try {
        const r = await fetch('/api/login-status', { method: 'POST' });
        const j = await r.json();
        setRows(j.rows || []);
      } catch { loadCached(); }
    })();
    const t = setInterval(loadCached, 5000);
    return () => clearInterval(t);
  }, [loadCached]);

  const checkAll = async () => {
    setBusyAll(true);
    try {
      const r = await fetch('/api/login-status', { method: 'POST' });
      const j = await r.json();
      setRows(j.rows || []);
    } finally {
      setBusyAll(false);
    }
  };

  const checkOne = async (id: string) => {
    setBusyIds((s) => new Set(s).add(id));
    try {
      const r = await fetch(`/api/login-status/${encodeURIComponent(id)}/check`, { method: 'POST' });
      const j = await r.json();
      if (j.source && j.result) {
        setRows((prev) =>
          (prev || []).map((row) => (row.source.id === id ? { source: j.source, result: j.result } : row)),
        );
      }
    } finally {
      setBusyIds((s) => {
        const next = new Set(s); next.delete(id); return next;
      });
    }
  };

  const refresh = (source: LoginSource) => {
    const r = source.refresh;
    if (r.kind === 'open-url') {
      window.open(r.url, '_blank', 'noopener');
    } else if (r.kind === 'show-command') {
      setShowCmd({ command: r.command, description: r.description });
    } else if (r.kind === 'open-settings') {
      window.dispatchEvent(new CustomEvent('forge:open-settings', { detail: { section: r.section } }));
      onClose();
    }
  };

  const grouped: Record<LoginCategory, Row[]> = { browser: [], token: [], external: [] };
  (rows || []).forEach((row) => grouped[row.source.category].push(row));

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onClick={onClose}>
      <div
        className="bg-[var(--bg-secondary)] border border-[var(--border)] rounded-lg w-[560px] max-h-[85vh] overflow-y-auto shadow-xl"
        onClick={(e) => e.stopPropagation()}
      >
        <div className="px-4 py-3 border-b border-[var(--border)] flex items-center justify-between">
          <h2 className="text-sm font-bold text-[var(--text-primary)]">Login Status</h2>
          <div className="flex items-center gap-2">
            <button
              onClick={checkAll}
              disabled={busyAll || rows === null}
              className="text-[10px] px-2 py-0.5 rounded border border-[var(--border)] text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50"
            >
              {busyAll ? 'Checking…' : 'Check all'}
            </button>
            <button onClick={onClose} className="text-[10px] text-[var(--text-secondary)] hover:text-[var(--text-primary)]">
              Close
            </button>
          </div>
        </div>

        {rows === null ? (
          <div className="p-6 text-center text-xs text-[var(--text-secondary)]">Loading…</div>
        ) : rows.length === 0 ? (
          <div className="p-6 text-center text-xs text-[var(--text-secondary)]">
            No login sources registered. Add a connector with a <code>test:</code> block or set <code>gitlab2faProbeRepo</code> in Settings.
          </div>
        ) : (
          <div className="p-4 space-y-5">
            {(['browser', 'token', 'external'] as LoginCategory[]).map((cat) => {
              const items = grouped[cat];
              if (!items.length) return null;
              return (
                <div key={cat}>
                  <h3 className="text-[10px] font-semibold text-[var(--text-secondary)] uppercase mb-2">
                    {CATEGORY_LABEL[cat]} ({items.length})
                  </h3>
                  <div className="space-y-1.5">
                    {items.map(({ source, result }) => {
                      const busy = busyIds.has(source.id);
                      const dot = !result ? '⚪' : result.ok ? '🟢' : '🔴';
                      return (
                        <div key={source.id} className="flex items-start gap-2 text-xs">
                          <span className="mt-0.5">{dot}</span>
                          <div className="flex-1 min-w-0">
                            <div className="flex items-center gap-2 flex-wrap">
                              <span className="text-[var(--text-primary)] font-medium">{source.label}</span>
                              {result ? (
                                <span className="text-[10px] text-[var(--text-secondary)]">{timeAgo(result.checked_at)}</span>
                              ) : (
                                <span className="text-[10px] text-gray-500">not checked</span>
                              )}
                              <div className="flex items-center gap-1 ml-auto">
                                <button
                                  onClick={() => checkOne(source.id)}
                                  disabled={busy || busyAll}
                                  className="text-[10px] px-1.5 py-0.5 rounded border border-[var(--border)] text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50"
                                >
                                  {busy ? '…' : 'Check'}
                                </button>
                                <button
                                  onClick={() => refresh(source)}
                                  className="text-[10px] px-1.5 py-0.5 rounded border border-[var(--border)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
                                >
                                  {source.refresh.kind === 'open-url' ? 'Open login' :
                                   source.refresh.kind === 'show-command' ? 'Refresh' :
                                   'Configure'}
                                </button>
                              </div>
                            </div>
                            {result?.message && (
                              <div className={`text-[10px] mt-0.5 ${result.ok ? 'text-[var(--text-secondary)]' : 'text-red-400'}`}>
                                {result.message}
                              </div>
                            )}
                            {source.detail && !result?.message && (
                              <div className="text-[10px] text-gray-500 mt-0.5">{source.detail}</div>
                            )}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              );
            })}
          </div>
        )}

        {showCmd && (
          <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60" onClick={() => setShowCmd(null)}>
            <div className="bg-[var(--bg-secondary)] border border-[var(--border)] rounded-lg p-4 w-[480px] shadow-xl" onClick={(e) => e.stopPropagation()}>
              <h3 className="text-sm font-bold mb-2 text-[var(--text-primary)]">Run this in a terminal</h3>
              <div className="text-[11px] text-[var(--text-secondary)] mb-2">{showCmd.description}</div>
              <pre className="bg-[var(--bg-tertiary)] p-2 rounded text-xs text-[var(--text-primary)] font-mono whitespace-pre-wrap break-all">
                {showCmd.command}
              </pre>
              <div className="mt-3 flex items-center justify-end gap-2">
                <button
                  onClick={() => { navigator.clipboard.writeText(showCmd.command); }}
                  className="text-[10px] px-2 py-1 rounded border border-[var(--border)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
                >
                  Copy
                </button>
                <button
                  onClick={() => setShowCmd(null)}
                  className="text-[10px] px-2 py-1 rounded border border-[var(--border)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
                >
                  Close
                </button>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
