/**
 * Settings → API Keys panel (Wave 2 AUTH-03 UI half).
 *
 * Consumes the Wave 1 resolver state endpoint at
 *   GET    /api/settings/hf-token/state
 *   POST   /api/settings/hf-token
 *   DELETE /api/settings/hf-token?also_clear_hf_cli={bool}
 *
 * Renders one row per source (App / Env / HF CLI) with set/unset indicator,
 * masked token preview, whoami username + green check on success, and an
 * "Active" badge on whichever row is currently serving the cascade.
 *
 * Threat T-02-02: the panel never displays the full token. The masked
 * value comes from the resolver state endpoint; the full token only
 * crosses the IPC boundary on Save (POST) and is cleared from local
 * state on success.
 *
 * Note: the GET + POST go through `apiJson` / `apiPost` from
 * `../../api/client` (the canonical base-URL site). The DELETE uses raw
 * fetch with the same `API` base so query params can be appended cleanly.
 */
import React, { useCallback, useEffect, useState } from 'react';
import { CheckCircle2, KeyRound, RefreshCw, Save, Trash2, XCircle } from 'lucide-react';
import { apiJson, apiPost, API } from '../../api/client';
import './ApiKeysPanel.css';

const SOURCE_LABELS = {
  app: 'OmniVoice (encrypted, recommended)',
  env: 'Environment variable',
  'hf-cli': 'HuggingFace CLI',
};

const SOURCE_HELP = {
  app: 'Stored encrypted in OmniVoice\'s local SQLite store. Set or clear here.',
  env: 'Set via HF_TOKEN in your shell. Read-only from the UI.',
  'hf-cli': 'Written by `huggingface-cli login`. Read-only from the UI.',
};

const EMPTY_STATE = {
  sources: [
    { source: 'app', set: false, masked: null, whoami_user: null, whoami_ok: false },
    { source: 'env', set: false, masked: null, whoami_user: null, whoami_ok: false },
    { source: 'hf-cli', set: false, masked: null, whoami_user: null, whoami_ok: false },
  ],
  active: null,
};

export default function ApiKeysPanel() {
  const [state, setState] = useState(EMPTY_STATE);
  const [loading, setLoading] = useState(false);
  const [tokenInput, setTokenInput] = useState('');
  const [saving, setSaving] = useState(false);
  const [clearOpen, setClearOpen] = useState(false);
  const [alsoClearCli, setAlsoClearCli] = useState(false);
  const [error, setError] = useState(null);

  const refresh = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const data = await apiJson('/api/settings/hf-token/state');
      setState(data);
    } catch (e) {
      setError(e?.message || 'Failed to load token state');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    refresh();
  }, [refresh]);

  const onSave = async () => {
    const token = tokenInput.trim();
    if (!token) return;
    setSaving(true);
    setError(null);
    try {
      await apiPost('/api/settings/hf-token', { token });
      setTokenInput('');
      await refresh();
    } catch (e) {
      setError(e?.message || 'Failed to save token');
    } finally {
      setSaving(false);
    }
  };

  const onClear = async () => {
    setSaving(true);
    setError(null);
    try {
      const qs = alsoClearCli ? '?also_clear_hf_cli=true' : '';
      const url = `${API}/api/settings/hf-token${qs}`;
      const res = await fetch(url, { method: 'DELETE' });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      setClearOpen(false);
      setAlsoClearCli(false);
      await refresh();
    } catch (e) {
      setError(e?.message || 'Failed to clear token');
    } finally {
      setSaving(false);
    }
  };

  return (
    <section className="apikeys-panel" aria-labelledby="apikeys-heading">
      <h3 id="apikeys-heading" className="apikeys-panel__title">
        <KeyRound size={14} /> HuggingFace token
      </h3>
      <p className="apikeys-panel__intro">
        OmniVoice walks three sources in priority order (App → Env → HF CLI).
        The first source with a token that survives a live <code>whoami</code> check
        is the <strong>Active</strong> source.
      </p>

      {error && (
        <div className="apikeys-panel__error" role="alert">
          {error}
        </div>
      )}

      <div className="apikeys-rows" role="table" aria-label="HF token sources">
        {state.sources.map((row) => {
          const isActive = state.active === row.source;
          return (
            <div
              key={row.source}
              className={`apikeys-row ${isActive ? 'apikeys-row--active' : ''}`}
              role="row"
              data-source={row.source}
            >
              <div className="apikeys-row__head">
                <span className="apikeys-row__name">{SOURCE_LABELS[row.source]}</span>
                {isActive && (
                  <span className="apikeys-badge apikeys-badge--active">Active</span>
                )}
              </div>
              <div className="apikeys-row__meta">
                {row.set ? (
                  <>
                    <span className="apikeys-row__set" aria-label="set">
                      <CheckCircle2 size={12} /> set
                    </span>
                    {row.masked && (
                      <code className="apikeys-row__masked">{row.masked}</code>
                    )}
                    {row.whoami_ok ? (
                      <span className="apikeys-row__whoami apikeys-row__whoami--ok">
                        <CheckCircle2 size={12} /> {row.whoami_user || 'verified'}
                      </span>
                    ) : (
                      <span className="apikeys-row__whoami apikeys-row__whoami--bad">
                        <XCircle size={12} /> whoami failed
                      </span>
                    )}
                  </>
                ) : (
                  <span className="apikeys-row__unset">
                    <XCircle size={12} /> not set
                  </span>
                )}
              </div>
              <p className="apikeys-row__help">{SOURCE_HELP[row.source]}</p>
              {row.source === 'app' && (
                <div className="apikeys-row__actions">
                  <input
                    type="password"
                    className="apikeys-input"
                    placeholder="hf_…"
                    aria-label="HuggingFace token"
                    value={tokenInput}
                    onChange={(e) => setTokenInput(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter') onSave();
                    }}
                    autoComplete="off"
                    spellCheck={false}
                  />
                  <button
                    type="button"
                    className="apikeys-btn apikeys-btn--save"
                    onClick={onSave}
                    disabled={!tokenInput.trim() || saving}
                  >
                    <Save size={12} /> Save
                  </button>
                  {row.set && (
                    <button
                      type="button"
                      className="apikeys-btn apikeys-btn--danger"
                      onClick={() => setClearOpen(true)}
                      disabled={saving}
                    >
                      <Trash2 size={12} /> Clear
                    </button>
                  )}
                </div>
              )}
            </div>
          );
        })}
      </div>

      <div className="apikeys-panel__footer">
        <button
          type="button"
          className="apikeys-btn apikeys-btn--ghost"
          onClick={refresh}
          disabled={loading}
          aria-label="Test now"
          title="Re-run whoami for every source"
        >
          <RefreshCw size={12} /> Test now
        </button>
      </div>

      {clearOpen && (
        <div className="apikeys-clear-dialog" role="dialog" aria-label="Clear token">
          <p>Clear the App-source HuggingFace token?</p>
          <label className="apikeys-checkbox">
            <input
              type="checkbox"
              checked={alsoClearCli}
              onChange={(e) => setAlsoClearCli(e.target.checked)}
            />{' '}
            Also clear <code>~/.cache/huggingface/token</code>
          </label>
          <div className="apikeys-clear-dialog__actions">
            <button
              type="button"
              className="apikeys-btn apikeys-btn--ghost"
              onClick={() => {
                setClearOpen(false);
                setAlsoClearCli(false);
              }}
            >
              Cancel
            </button>
            <button
              type="button"
              className="apikeys-btn apikeys-btn--danger"
              onClick={onClear}
              disabled={saving}
            >
              <Trash2 size={12} /> Clear token
            </button>
          </div>
        </div>
      )}
    </section>
  );
}
