/**
 * Settings page — exposes the encrypted-secrets catalogue
 * (`SETTINGS_CATALOGUE` in `src/core/settings/keys.ts`) as a simple form.
 *
 * Why a dedicated page (not part of the main Settings-Drawer)? The drawer
 * holds workspace/prompt/conversion config which is workspace-scoped and
 * tied to the editing flow. This page is plugin-scoped configuration —
 * AI keys, adapter credentials — that integrators set once at install
 * time and rarely revisit.
 *
 * The page never reads back stored secret values. Each input shows an
 * "(set)" or "(empty)" hint based on `entries[].hasValue` from the API.
 */

'use client';

import * as React from 'react';
import { useEffect, useState } from 'react';

interface CatalogueEntry {
  key: string;
  kind: 'plain' | 'secret';
  description?: string;
  hasValue: boolean;
}

interface CatalogueResponse {
  entries: CatalogueEntry[];
}

const SECRET_LABELS: Record<string, string> = {
  openrouter_api_key: 'OpenRouter API Key',
  fal_api_key: 'fal.ai API Key',
  send_provider_config: 'Send Provider Config (JSON)',
  crm_adapter_config: 'CRM Adapter Config (JSON)',
  system_prompt_generate: 'System Prompt — Generate',
  system_prompt_suggest: 'System Prompt — Suggest',
  system_prompt_image: 'System Prompt — Image',
  conversion_polling: 'Conversion Polling Config (JSON)',
};

export default function SettingsPage(): React.ReactElement {
  const [entries, setEntries] = useState<CatalogueEntry[] | null>(null);
  const [pending, setPending] = useState<Record<string, string>>({});
  const [savingKey, setSavingKey] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [flash, setFlash] = useState<string | null>(null);

  async function load(): Promise<void> {
    setError(null);
    try {
      const res = await fetch('/api/settings?view=catalogue');
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const json: CatalogueResponse = await res.json();
      setEntries(json.entries);
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    }
  }

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

  async function save(key: string): Promise<void> {
    setError(null);
    setSavingKey(key);
    try {
      const res = await fetch('/api/settings', {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ values: { [key]: pending[key] ?? '' } }),
      });
      if (!res.ok) {
        const text = await res.text();
        throw new Error(`HTTP ${res.status}: ${text}`);
      }
      const data = await res.json();
      setEntries(data.entries);
      setPending((p) => {
        const { [key]: _, ...rest } = p;
        return rest;
      });
      setFlash(`Saved: ${SECRET_LABELS[key] ?? key}`);
      setTimeout(() => setFlash(null), 3000);
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setSavingKey(null);
    }
  }

  if (!entries) {
    return (
      <div className="mx-auto max-w-3xl p-8">
        <h1 className="text-2xl font-semibold mb-4">Plugin Settings</h1>
        {error ? <p className="text-red-600">{error}</p> : <p>Loading…</p>}
      </div>
    );
  }

  const secrets = entries.filter((e) => e.kind === 'secret');
  const plains = entries.filter((e) => e.kind === 'plain');

  return (
    <div className="mx-auto max-w-3xl p-8">
      <header className="mb-8">
        <h1 className="text-2xl font-semibold">Plugin Settings</h1>
        <p className="text-sm text-gray-600 mt-1">
          AI keys, adapter credentials and system prompts. Secrets are encrypted at rest
          (AES-256-GCM with the <code className="rounded bg-gray-100 px-1">APP_ENCRYPTION_KEY</code>{' '}
          env-var). Stored values are never read back into this UI — the hint next to each
          field shows whether a value is configured.
        </p>
      </header>

      {flash && (
        <div className="mb-4 rounded border border-green-300 bg-green-50 px-3 py-2 text-sm text-green-800">
          {flash}
        </div>
      )}
      {error && (
        <div className="mb-4 rounded border border-red-300 bg-red-50 px-3 py-2 text-sm text-red-800">
          {error}
        </div>
      )}

      <Section title="Secrets" hint="Encrypted at rest. Save an empty value to clear.">
        {secrets.map((entry) => (
          <Field
            key={entry.key}
            entry={entry}
            pendingValue={pending[entry.key] ?? ''}
            onChange={(v) => setPending((p) => ({ ...p, [entry.key]: v }))}
            onSave={() => save(entry.key)}
            saving={savingKey === entry.key}
          />
        ))}
      </Section>

      <Section title="Plain Settings" hint="Stored as-is (not encrypted).">
        {plains.map((entry) => (
          <Field
            key={entry.key}
            entry={entry}
            pendingValue={pending[entry.key] ?? ''}
            onChange={(v) => setPending((p) => ({ ...p, [entry.key]: v }))}
            onSave={() => save(entry.key)}
            saving={savingKey === entry.key}
          />
        ))}
      </Section>
    </div>
  );
}

function Section({
  title,
  hint,
  children,
}: {
  title: string;
  hint?: string;
  children: React.ReactNode;
}): React.ReactElement {
  return (
    <section className="mb-8">
      <h2 className="text-lg font-semibold mb-1">{title}</h2>
      {hint && <p className="text-sm text-gray-500 mb-4">{hint}</p>}
      <div className="space-y-4">{children}</div>
    </section>
  );
}

function Field({
  entry,
  pendingValue,
  onChange,
  onSave,
  saving,
}: {
  entry: CatalogueEntry;
  pendingValue: string;
  onChange: (v: string) => void;
  onSave: () => void;
  saving: boolean;
}): React.ReactElement {
  const isSecret = entry.kind === 'secret';
  const looksLikeJson = entry.key.endsWith('_config') || entry.key === 'conversion_polling';
  const inputType = isSecret && !looksLikeJson ? 'password' : 'text';

  return (
    <div className="rounded border border-gray-200 p-4">
      <div className="flex items-baseline justify-between gap-4 mb-1">
        <label htmlFor={entry.key} className="text-sm font-medium">
          {SECRET_LABELS[entry.key] ?? entry.key}
        </label>
        <span
          className={`text-xs ${entry.hasValue ? 'text-green-700' : 'text-gray-400'}`}
        >
          {entry.hasValue ? '✓ set' : '— empty'}
        </span>
      </div>
      {entry.description && (
        <p className="text-xs text-gray-500 mb-2">{entry.description}</p>
      )}
      {looksLikeJson ? (
        <textarea
          id={entry.key}
          className="block w-full rounded border border-gray-300 px-3 py-2 text-sm font-mono"
          rows={4}
          placeholder={entry.hasValue ? '(leave empty to keep)' : 'Paste JSON here…'}
          value={pendingValue}
          onChange={(e) => onChange(e.target.value)}
          disabled={saving}
        />
      ) : (
        <input
          id={entry.key}
          type={inputType}
          className="block w-full rounded border border-gray-300 px-3 py-2 text-sm"
          placeholder={entry.hasValue ? '(leave empty to keep)' : 'Paste value here…'}
          value={pendingValue}
          onChange={(e) => onChange(e.target.value)}
          disabled={saving}
        />
      )}
      <div className="mt-2 flex items-center gap-2">
        <button
          type="button"
          onClick={onSave}
          disabled={saving || pendingValue.length === 0}
          className="rounded bg-black px-3 py-1.5 text-sm text-white disabled:opacity-50"
        >
          {saving ? 'Saving…' : 'Save'}
        </button>
        {entry.hasValue && (
          <button
            type="button"
            onClick={() => {
              onChange('');
              setTimeout(onSave, 0);
            }}
            disabled={saving}
            className="text-xs text-red-600 underline"
          >
            Clear stored value
          </button>
        )}
      </div>
    </div>
  );
}
