import { useEffect, useState, useCallback } from "react";
import {
  admin,
  endpoints,
  webhooks,
  ApiError,
} from "../api/client";
import type {
  EndpointResponse,
  WebhookResponse,
  WebhookCreate,
} from "../api/client";

// ---------------------------------------------------------------------------
// Types for admin settings / stats
// ---------------------------------------------------------------------------

interface AdminSettings {
  guest_access_enabled: boolean;
  default_endpoint_id: string | null;
  token_budget_daily: number | null;
  token_budget_monthly: number | null;
  api_keys: ApiKeyEntry[];
}

interface ApiKeyEntry {
  id: string;
  label: string;
  prefix: string;
  created_at: string;
}

interface SystemStats {
  total_runs: number;
  total_experiments: number;
  total_projects: number;
  cache_entries: number;
  cache_hit_rate: number;
  storage_bytes: number;
  tokens_spent: number;
}

function defaultSettings(): AdminSettings {
  return {
    guest_access_enabled: false,
    default_endpoint_id: null,
    token_budget_daily: null,
    token_budget_monthly: null,
    api_keys: [],
  };
}

function defaultStats(): SystemStats {
  return {
    total_runs: 0,
    total_experiments: 0,
    total_projects: 0,
    cache_entries: 0,
    cache_hit_rate: 0,
    storage_bytes: 0,
    tokens_spent: 0,
  };
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function formatBytes(bytes: number): string {
  if (bytes === 0) return "0 B";
  const units = ["B", "KB", "MB", "GB", "TB"];
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  const val = bytes / Math.pow(1024, i);
  return `${val.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
}

function formatNumber(n: number): string {
  return n.toLocaleString();
}

// ---------------------------------------------------------------------------
// Section Card wrapper
// ---------------------------------------------------------------------------

function SectionCard({
  title,
  children,
}: {
  title: string;
  children: React.ReactNode;
}) {
  return (
    <div className="rounded-xl bg-white dark:bg-slate-800 p-6 shadow-md ring-1 ring-slate-200 dark:ring-slate-700">
      <h2 className="mb-4 text-lg font-semibold text-slate-900 dark:text-white">
        {title}
      </h2>
      {children}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Settings Section
// ---------------------------------------------------------------------------

function SettingsSection({
  settings,
  endpointList,
  onUpdate,
  saving,
}: {
  settings: AdminSettings;
  endpointList: EndpointResponse[];
  onUpdate: (patch: Partial<AdminSettings>) => void;
  saving: boolean;
}) {
  return (
    <SectionCard title="Settings">
      <div className="space-y-5">
        {/* Guest access toggle */}
        <div className="flex items-center justify-between">
          <div>
            <p className="text-sm font-medium text-slate-700 dark:text-slate-300">
              Guest Access
            </p>
            <p className="text-xs text-slate-500 dark:text-slate-400">
              Allow unauthenticated users to view experiments.
            </p>
          </div>
          <button
            type="button"
            role="switch"
            aria-checked={settings.guest_access_enabled}
            data-testid="guest-access-toggle"
            disabled={saving}
            onClick={() =>
              onUpdate({
                guest_access_enabled: !settings.guest_access_enabled,
              })
            }
            className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 ${
              settings.guest_access_enabled
                ? "bg-indigo-600"
                : "bg-slate-300 dark:bg-slate-600"
            }`}
          >
            <span
              className={`pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transition-transform duration-200 ${
                settings.guest_access_enabled
                  ? "translate-x-5"
                  : "translate-x-0"
              }`}
            />
          </button>
        </div>

        {/* Default endpoint */}
        <div>
          <label
            htmlFor="default-endpoint"
            className="mb-1.5 block text-sm font-medium text-slate-700 dark:text-slate-300"
          >
            Default Endpoint
          </label>
          <select
            id="default-endpoint"
            data-testid="default-endpoint-select"
            value={settings.default_endpoint_id ?? ""}
            disabled={saving}
            onChange={(e) =>
              onUpdate({
                default_endpoint_id: e.target.value || null,
              })
            }
            className="w-full rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-3 py-2 text-sm text-slate-900 dark:text-white focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition"
          >
            <option value="">None</option>
            {endpointList.map((ep) => (
              <option key={ep.id} value={ep.id}>
                {ep.name}
              </option>
            ))}
          </select>
        </div>

        {/* Token budgets */}
        <div className="grid grid-cols-2 gap-4">
          <div>
            <label
              htmlFor="budget-daily"
              className="mb-1.5 block text-sm font-medium text-slate-700 dark:text-slate-300"
            >
              Daily Token Budget
            </label>
            <input
              id="budget-daily"
              type="number"
              min={0}
              data-testid="budget-daily"
              value={settings.token_budget_daily ?? ""}
              disabled={saving}
              onChange={(e) =>
                onUpdate({
                  token_budget_daily: e.target.value
                    ? Number(e.target.value)
                    : null,
                })
              }
              placeholder="Unlimited"
              className="w-full rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-3 py-2 text-sm text-slate-900 dark:text-white placeholder-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition"
            />
          </div>
          <div>
            <label
              htmlFor="budget-monthly"
              className="mb-1.5 block text-sm font-medium text-slate-700 dark:text-slate-300"
            >
              Monthly Token Budget
            </label>
            <input
              id="budget-monthly"
              type="number"
              min={0}
              data-testid="budget-monthly"
              value={settings.token_budget_monthly ?? ""}
              disabled={saving}
              onChange={(e) =>
                onUpdate({
                  token_budget_monthly: e.target.value
                    ? Number(e.target.value)
                    : null,
                })
              }
              placeholder="Unlimited"
              className="w-full rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-3 py-2 text-sm text-slate-900 dark:text-white placeholder-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition"
            />
          </div>
        </div>
      </div>
    </SectionCard>
  );
}

// ---------------------------------------------------------------------------
// API Keys Section
// ---------------------------------------------------------------------------

function ApiKeysSection({
  keys,
  onGenerate,
  onRevoke,
  generating,
}: {
  keys: ApiKeyEntry[];
  onGenerate: (label: string) => void;
  onRevoke: (id: string) => void;
  generating: boolean;
}) {
  const [newLabel, setNewLabel] = useState("");

  function handleGenerate(e: React.FormEvent) {
    e.preventDefault();
    if (!newLabel.trim()) return;
    onGenerate(newLabel.trim());
    setNewLabel("");
  }

  return (
    <SectionCard title="API Keys">
      <form onSubmit={handleGenerate} className="mb-4 flex gap-2">
        <input
          type="text"
          value={newLabel}
          onChange={(e) => setNewLabel(e.target.value)}
          placeholder="Key label (e.g. CI pipeline)"
          data-testid="api-key-label"
          disabled={generating}
          className="flex-1 rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-3 py-2 text-sm text-slate-900 dark:text-white placeholder-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition"
        />
        <button
          type="submit"
          disabled={generating || !newLabel.trim()}
          data-testid="generate-key-btn"
          className="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed transition"
        >
          {generating ? "Generating..." : "Generate"}
        </button>
      </form>

      {keys.length === 0 ? (
        <p className="text-sm text-slate-500 dark:text-slate-400">
          No API keys generated yet.
        </p>
      ) : (
        <ul className="divide-y divide-slate-200 dark:divide-slate-700">
          {keys.map((key) => (
            <li
              key={key.id}
              className="flex items-center justify-between py-3"
            >
              <div>
                <p className="text-sm font-medium text-slate-900 dark:text-white">
                  {key.label}
                </p>
                <p className="text-xs text-slate-500 dark:text-slate-400">
                  {key.prefix}... &middot; Created{" "}
                  {new Date(key.created_at).toLocaleDateString()}
                </p>
              </div>
              <button
                type="button"
                onClick={() => onRevoke(key.id)}
                data-testid={`revoke-key-${key.id}`}
                className="rounded-lg px-3 py-1.5 text-xs font-medium text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/30 transition"
              >
                Revoke
              </button>
            </li>
          ))}
        </ul>
      )}
    </SectionCard>
  );
}

// ---------------------------------------------------------------------------
// System Stats Section
// ---------------------------------------------------------------------------

function StatsSection({ stats }: { stats: SystemStats }) {
  const statItems = [
    { label: "Total Runs", value: formatNumber(stats.total_runs) },
    {
      label: "Total Experiments",
      value: formatNumber(stats.total_experiments),
    },
    { label: "Total Projects", value: formatNumber(stats.total_projects) },
    { label: "Cache Entries", value: formatNumber(stats.cache_entries) },
    {
      label: "Cache Hit Rate",
      value: `${(stats.cache_hit_rate * 100).toFixed(1)}%`,
    },
    { label: "Storage Usage", value: formatBytes(stats.storage_bytes) },
    { label: "Tokens Spent", value: formatNumber(stats.tokens_spent) },
  ];

  return (
    <SectionCard title="System Stats">
      <div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
        {statItems.map((item) => (
          <div
            key={item.label}
            className="rounded-lg bg-slate-50 dark:bg-slate-700/50 p-3"
          >
            <p className="text-xs text-slate-500 dark:text-slate-400">
              {item.label}
            </p>
            <p
              className="mt-1 text-lg font-semibold text-slate-900 dark:text-white"
              data-testid={`stat-${item.label.toLowerCase().replace(/\s+/g, "-")}`}
            >
              {item.value}
            </p>
          </div>
        ))}
      </div>
    </SectionCard>
  );
}

// ---------------------------------------------------------------------------
// Webhooks Section
// ---------------------------------------------------------------------------

const EVENT_TYPES = [
  "run.started",
  "run.completed",
  "run.failed",
  "sweep.started",
  "sweep.completed",
  "new_best_found",
];

function WebhooksSection({
  webhookList,
  onDelete,
  onCreate,
  creating,
}: {
  webhookList: WebhookResponse[];
  onDelete: (id: string) => void;
  onCreate: (data: WebhookCreate) => void;
  creating: boolean;
}) {
  const [showForm, setShowForm] = useState(false);
  const [eventType, setEventType] = useState(EVENT_TYPES[0]);
  const [url, setUrl] = useState("");

  function handleCreate(e: React.FormEvent) {
    e.preventDefault();
    if (!url.trim()) return;
    onCreate({ event_type: eventType, url: url.trim() });
    setUrl("");
    setShowForm(false);
  }

  return (
    <SectionCard title="Webhooks">
      <div className="mb-4 flex items-center justify-between">
        <p className="text-sm text-slate-500 dark:text-slate-400">
          {webhookList.length} webhook{webhookList.length !== 1 ? "s" : ""}{" "}
          configured
        </p>
        <button
          type="button"
          onClick={() => setShowForm(!showForm)}
          data-testid="add-webhook-btn"
          className="rounded-lg bg-indigo-600 px-3 py-1.5 text-xs font-semibold text-white shadow-sm hover:bg-indigo-500 transition"
        >
          {showForm ? "Cancel" : "Add Webhook"}
        </button>
      </div>

      {showForm && (
        <form
          onSubmit={handleCreate}
          className="mb-4 rounded-lg border border-slate-200 dark:border-slate-700 p-4 space-y-3"
          data-testid="webhook-form"
        >
          <div>
            <label
              htmlFor="webhook-event"
              className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300"
            >
              Event Type
            </label>
            <select
              id="webhook-event"
              value={eventType}
              onChange={(e) => setEventType(e.target.value)}
              disabled={creating}
              className="w-full rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-3 py-2 text-sm text-slate-900 dark:text-white focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition"
            >
              {EVENT_TYPES.map((et) => (
                <option key={et} value={et}>
                  {et}
                </option>
              ))}
            </select>
          </div>
          <div>
            <label
              htmlFor="webhook-url"
              className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300"
            >
              URL
            </label>
            <input
              id="webhook-url"
              type="url"
              value={url}
              onChange={(e) => setUrl(e.target.value)}
              placeholder="https://example.com/webhook"
              data-testid="webhook-url-input"
              disabled={creating}
              className="w-full rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-3 py-2 text-sm text-slate-900 dark:text-white placeholder-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition"
            />
          </div>
          <button
            type="submit"
            disabled={creating || !url.trim()}
            data-testid="create-webhook-btn"
            className="rounded-lg bg-emerald-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-emerald-500 disabled:opacity-50 disabled:cursor-not-allowed transition"
          >
            {creating ? "Creating..." : "Create Webhook"}
          </button>
        </form>
      )}

      {webhookList.length === 0 && !showForm ? (
        <p className="text-sm text-slate-500 dark:text-slate-400">
          No webhooks configured.
        </p>
      ) : (
        <ul className="divide-y divide-slate-200 dark:divide-slate-700">
          {webhookList.map((wh) => (
            <li
              key={wh.id}
              className="flex items-center justify-between py-3"
            >
              <div className="min-w-0 flex-1">
                <div className="flex items-center gap-2">
                  <span
                    className={`inline-block h-2 w-2 rounded-full ${
                      wh.is_active
                        ? "bg-green-500"
                        : "bg-slate-400 dark:bg-slate-500"
                    }`}
                  />
                  <p className="text-sm font-medium text-slate-900 dark:text-white truncate">
                    {wh.event_type}
                  </p>
                </div>
                <p className="text-xs text-slate-500 dark:text-slate-400 truncate mt-0.5">
                  {wh.url}
                </p>
              </div>
              <button
                type="button"
                onClick={() => onDelete(wh.id)}
                data-testid={`delete-webhook-${wh.id}`}
                className="ml-3 shrink-0 rounded-lg px-3 py-1.5 text-xs font-medium text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/30 transition"
              >
                Delete
              </button>
            </li>
          ))}
        </ul>
      )}
    </SectionCard>
  );
}

// ---------------------------------------------------------------------------
// Admin Page
// ---------------------------------------------------------------------------

export default function AdminPage() {
  const [settings, setSettings] = useState<AdminSettings>(defaultSettings());
  const [stats, setStats] = useState<SystemStats>(defaultStats());
  const [endpointList, setEndpointList] = useState<EndpointResponse[]>([]);
  const [webhookList, setWebhookList] = useState<WebhookResponse[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [saving, setSaving] = useState(false);
  const [generating, setGenerating] = useState(false);
  const [creatingWebhook, setCreatingWebhook] = useState(false);
  const [saveMessage, setSaveMessage] = useState<string | null>(null);

  const loadData = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const [settingsResp, statsResp, endpointsResp, webhooksResp] =
        await Promise.all([
          admin.getSettings(),
          admin.getStats(),
          endpoints.list(),
          webhooks.list(),
        ]);

      setSettings({
        ...defaultSettings(),
        ...(settingsResp as Partial<AdminSettings>),
      });
      setStats({ ...defaultStats(), ...(statsResp as Partial<SystemStats>) });
      setEndpointList(endpointsResp.items);
      setWebhookList(webhooksResp.items);
    } catch (err: unknown) {
      if (err instanceof ApiError) {
        setError(`Failed to load admin data (${err.status}).`);
      } else {
        setError("Network error. Is the server running?");
      }
    } finally {
      setLoading(false);
    }
  }, []);

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

  async function handleUpdateSettings(patch: Partial<AdminSettings>) {
    const updated = { ...settings, ...patch };
    setSettings(updated);
    setSaving(true);
    setSaveMessage(null);
    try {
      await admin.updateSettings(
        updated as unknown as Record<string, unknown>,
      );
      setSaveMessage("Settings saved.");
      setTimeout(() => setSaveMessage(null), 2000);
    } catch {
      setSaveMessage("Failed to save settings.");
    } finally {
      setSaving(false);
    }
  }

  async function handleGenerateKey(label: string) {
    setGenerating(true);
    try {
      const resp = await admin.updateSettings({
        action: "generate_api_key",
        label,
      });
      const newKey = resp as unknown as {
        api_key?: ApiKeyEntry;
        api_keys?: ApiKeyEntry[];
      };
      if (newKey.api_keys) {
        setSettings((prev) => ({ ...prev, api_keys: newKey.api_keys! }));
      } else if (newKey.api_key) {
        setSettings((prev) => ({
          ...prev,
          api_keys: [...prev.api_keys, newKey.api_key!],
        }));
      }
    } catch {
      setSaveMessage("Failed to generate API key.");
      setTimeout(() => setSaveMessage(null), 2000);
    } finally {
      setGenerating(false);
    }
  }

  async function handleRevokeKey(keyId: string) {
    try {
      await admin.updateSettings({
        action: "revoke_api_key",
        key_id: keyId,
      });
      setSettings((prev) => ({
        ...prev,
        api_keys: prev.api_keys.filter((k) => k.id !== keyId),
      }));
    } catch {
      setSaveMessage("Failed to revoke API key.");
      setTimeout(() => setSaveMessage(null), 2000);
    }
  }

  async function handleCreateWebhook(data: WebhookCreate) {
    setCreatingWebhook(true);
    try {
      const created = await webhooks.create(data);
      setWebhookList((prev) => [...prev, created]);
    } catch {
      setSaveMessage("Failed to create webhook.");
      setTimeout(() => setSaveMessage(null), 2000);
    } finally {
      setCreatingWebhook(false);
    }
  }

  async function handleDeleteWebhook(id: string) {
    try {
      await webhooks.delete(id);
      setWebhookList((prev) => prev.filter((w) => w.id !== id));
    } catch {
      setSaveMessage("Failed to delete webhook.");
      setTimeout(() => setSaveMessage(null), 2000);
    }
  }

  return (
    <div className="min-h-full bg-gradient-to-br from-indigo-50/50 to-slate-100/50 dark:from-slate-900/50 dark:to-slate-800/50 px-4 py-8 sm:px-6 lg:px-8">
      <div className="mx-auto max-w-4xl">
        {/* Header */}
        <div className="mb-8">
          <h1 className="text-3xl font-bold text-slate-900 dark:text-white">
            Admin
          </h1>
          <p className="mt-1 text-slate-500 dark:text-slate-400">
            System administration and settings.
          </p>
          {saveMessage && (
            <p
              className="mt-2 text-sm font-medium text-indigo-600 dark:text-indigo-400"
              data-testid="save-message"
            >
              {saveMessage}
            </p>
          )}
        </div>

        {/* Loading */}
        {loading && (
          <p className="text-center text-slate-500 dark:text-slate-400 animate-pulse py-16">
            Loading admin data...
          </p>
        )}

        {/* Error */}
        {!loading && error && (
          <div
            role="alert"
            className="rounded-xl bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 p-6 text-center"
          >
            <p className="text-red-700 dark:text-red-300">{error}</p>
            <button
              type="button"
              onClick={loadData}
              className="mt-3 text-sm font-medium text-indigo-600 dark:text-indigo-400 hover:text-indigo-500"
            >
              Retry
            </button>
          </div>
        )}

        {/* Content */}
        {!loading && !error && (
          <div className="space-y-6">
            <SettingsSection
              settings={settings}
              endpointList={endpointList}
              onUpdate={handleUpdateSettings}
              saving={saving}
            />

            <ApiKeysSection
              keys={settings.api_keys}
              onGenerate={handleGenerateKey}
              onRevoke={handleRevokeKey}
              generating={generating}
            />

            <StatsSection stats={stats} />

            <WebhooksSection
              webhookList={webhookList}
              onDelete={handleDeleteWebhook}
              onCreate={handleCreateWebhook}
              creating={creatingWebhook}
            />
          </div>
        )}
      </div>
    </div>
  );
}
