// components/integrations.jsx — Webhook integrations panel.
// Manages GitHub, GitLab, and Jira webhooks from the dashboard.

const useState = React.useState;
const useEffect = React.useEffect;
const useCallback = React.useCallback;
const useMemo = React.useMemo;

const SUPPORTED_WEBHOOK_SYSTEMS = [
  {
    id: "github",
    label: "GitHub",
    description: "Sync ticket status changes and orchestrator review comments to GitHub issues.",
  },
  {
    id: "gitlab",
    label: "GitLab",
    description: "Sync ticket status changes and orchestrator review comments to GitLab issues.",
  },
  {
    id: "jira",
    label: "Jira",
    description: "Sync ticket status changes and orchestrator review comments to Jira issues.",
  },
];

// Platform-specific configuration guides
const PLATFORM_GUIDES = {
  github: {
    settingsUrl: "https://github.com/{owner}/{repo}/settings/hooks",
    docsUrl: "https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks",
    steps: [
      "Go to your repository → Settings → Webhooks",
      "Click 'Add webhook'",
      "Paste the webhook URL below into 'Payload URL'",
      "Set Content type to 'application/json'",
      "Select events: Issues, Issue comments, Pull requests (optional)",
      "Click 'Add webhook'"
    ],
    quickLink: "https://github.com/settings/hooks"
  },
  gitlab: {
    settingsUrl: "https://gitlab.com/{owner}/{repo}/-/settings/integrations",
    docsUrl: "https://docs.gitlab.com/ee/user/project/integrations/webhooks.html",
    steps: [
      "Go to your project → Settings → Webhooks",
      "Paste the webhook URL below into 'URL'",
      "Select Trigger events: Issues, Comments",
      "Optional: Enable SSL verification",
      "Click 'Add webhook'"
    ],
    quickLink: "https://gitlab.com/dashboard/projects"
  },
  jira: {
    settingsUrl: "https://{domain}.atlassian.net/plugins/servlet/webhooks",
    docsUrl: "https://developer.atlassian.com/server/jira/platform/webhooks/",
    steps: [
      "Go to Jira Administration → System → WebHooks",
      "Click 'Create a WebHook'",
      "Name: 'Proxym Sync'",
      "Paste the webhook URL below into 'URL'",
      "Select events: Issue created, Issue updated, Comment created",
      "Click 'Create'"
    ],
    quickLink: "https://support.atlassian.com/jira-cloud-administration/docs/manage-webhooks/"
  }
};

const WEBHOOK_PLACEHOLDERS = {
  github: "https://example.com/webhooks/github",
  gitlab: "https://example.com/webhooks/gitlab",
  jira: "https://example.com/webhooks/jira",
};

// Build the proxym webhook endpoint URL based on current origin
function _buildWebhookBaseUrl() {
  if (typeof globalThis === "undefined" || !globalThis.location) {
    return "http://localhost:4001";
  }
  const origin = globalThis.location.origin;
  // Remove /dashboard-ui or similar paths, keep base
  return origin.replace(/\/dashboard.*$/, "");
}

function _getProxymWebhookUrl(system) {
  const base = _buildWebhookBaseUrl();
  return `${base}/dashboard/integrations/webhooks/${system}`;
}

// Copy to clipboard helper
async function _copyToClipboard(text) {
  try {
    if (globalThis.navigator?.clipboard) {
      await globalThis.navigator.clipboard.writeText(text);
      return true;
    }
    // Fallback
    const textarea = globalThis.document?.createElement("textarea");
    if (!textarea) return false;
    textarea.value = text;
    textarea.style.position = "fixed";
    textarea.style.opacity = "0";
    globalThis.document.body.appendChild(textarea);
    textarea.select();
    const success = globalThis.document.execCommand("copy");
    globalThis.document.body.removeChild(textarea);
    return success;
  } catch (_err) {
    return false;
  }
}

function _systemMeta(system) {
  return SUPPORTED_WEBHOOK_SYSTEMS.find((item) => item.id === system) || {
    id: system,
    label: system,
    description: "",
  };
}

function _extractErrorMessage(response, fallback) {
  if (!response) return fallback;
  if (typeof response === "string") return response;
  if (response.body) {
    if (typeof response.body === "string") return response.body;
    if (typeof response.body?.detail === "string") return response.body.detail;
    if (typeof response.body?.message === "string") return response.body.message;
  }
  if (typeof response.detail === "string") return response.detail;
  if (typeof response.message === "string") return response.message;
  return fallback;
}

function _formatWebhookTime(value) {
  if (!value) return "—";
  try {
    return new Date(value * 1000).toLocaleString();
  } catch (_err) {
    return "—";
  }
}

function useWebhookIntegrations() {
  const [webhooks, setWebhooks] = useState([]);
  const [loading, setLoading] = useState(true);
  const [savingSystem, setSavingSystem] = useState("");
  const [testingSystem, setTestingSystem] = useState("");
  const [lastTestResult, setLastTestResult] = useState({ system: "", success: null, time: null });
  const [message, setMessage] = useState({ kind: "", text: "" });
  const [form, setForm] = useState({
    system: "github",
    url: "",
  });

  const refresh = useCallback(async () => {
    setLoading(true);
    try {
      const data = await get("/dashboard/integrations/webhooks");
      if (data && data.ok === false) {
        throw new Error(_extractErrorMessage(data, "Failed to load webhooks"));
      }
      setWebhooks(Array.isArray(data) ? data : data?.webhooks || []);
      setMessage((current) => (current.kind === "error" ? { kind: "", text: "" } : current));
    } catch (err) {
      setWebhooks([]);
      setMessage({ kind: "error", text: err?.message || "Failed to load webhooks" });
    } finally {
      setLoading(false);
    }
  }, []);

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

  // SSE: subscribe to webhook events for real-time updates
  useEffect(() => {
    if (!globalThis.SSEService) {
      // Fallback to polling if SSE service unavailable
      const timer = setInterval(refresh, 30000);
      return () => clearInterval(timer);
    }

    const webhookEvents = new Set([
      "WebhookRegistered", "WebhookUpdated", "WebhookDeleted", "WebhookTested"
    ]);
    const unsubscribe = globalThis.SSEService.subscribe(
      "IntegrationsPanel",
      webhookEvents,
      (event) => {
        // Update last test result for visual feedback
        if (event.event_type === "WebhookTested" && event.data) {
          setLastTestResult({
            system: event.data.system,
            success: event.data.success,
            time: event.timestamp
          });
        }
        // Refresh webhook list
        refresh();
      }
    );

    return () => {
      unsubscribe();
    };
  }, [refresh]);

  const registerWebhook = useCallback(async (event) => {
    event.preventDefault();
    const url = form.url.trim();
    if (!url) {
      setMessage({ kind: "error", text: "Provide a webhook URL first." });
      return;
    }

    setSavingSystem(form.system);
    try {
      const response = await post("/dashboard/integrations/webhooks", {
        system: form.system,
        url,
      });
      if (response && response.ok === false) {
        throw new Error(_extractErrorMessage(response, "Failed to register webhook"));
      }
      setMessage({ kind: "success", text: `Registered ${form.system} webhook.` });
      setForm((current) => ({ ...current, url: "" }));
      await refresh();
    } catch (err) {
      setMessage({ kind: "error", text: err?.message || "Failed to register webhook" });
    } finally {
      setSavingSystem("");
    }
  }, [form.system, form.url, refresh]);

  const deleteWebhook = useCallback(async (system) => {
    if (globalThis.confirm && !globalThis.confirm(`Delete the ${system} webhook?`)) {
      return;
    }

    setSavingSystem(system);
    try {
      const response = await del(`/dashboard/integrations/webhooks/${system}`);
      if (response && response.ok === false) {
        throw new Error(_extractErrorMessage(response, "Failed to delete webhook"));
      }
      setMessage({ kind: "success", text: `Deleted ${system} webhook.` });
      setLastTestResult((current) => current.system === system ? { system: "", success: null, time: null } : current);
      await refresh();
    } catch (err) {
      setMessage({ kind: "error", text: err?.message || "Failed to delete webhook" });
    } finally {
      setSavingSystem("");
    }
  }, [refresh]);

  const testWebhook = useCallback(async (system, url) => {
    setTestingSystem(system);
    try {
      const response = await post(
        `/dashboard/integrations/webhooks/test?system=${encodeURIComponent(system)}&url=${encodeURIComponent(url)}`,
        {}
      );
      if (response && response.ok === false) {
        throw new Error(_extractErrorMessage(response, "Failed to test webhook"));
      }
      setMessage({ kind: "success", text: `Test payload sent to ${system} successfully.` });
    } catch (err) {
      setMessage({ kind: "error", text: err?.message || "Failed to test webhook" });
      setLastTestResult({ system, success: false, time: Date.now() / 1000 });
    } finally {
      setTestingSystem("");
    }
  }, []);

  return {
    webhooks,
    loading,
    form,
    setForm,
    message,
    savingSystem,
    testingSystem,
    lastTestResult,
    refresh,
    registerWebhook,
    deleteWebhook,
    testWebhook,
  };
}

function IntegrationsPanel() {
  const {
    webhooks,
    loading,
    form,
    setForm,
    message,
    savingSystem,
    testingSystem,
    lastTestResult,
    registerWebhook,
    deleteWebhook,
    testWebhook,
  } = useWebhookIntegrations();

  const [copiedUrl, setCopiedUrl] = useState(null);
  const [expandedGuide, setExpandedGuide] = useState(null);

  const proxymWebhookUrl = useMemo(() => _getProxymWebhookUrl(form.system), [form.system]);
  const guide = PLATFORM_GUIDES[form.system];

  const handleCopyUrl = useCallback(async () => {
    const success = await _copyToClipboard(proxymWebhookUrl);
    if (success) {
      setCopiedUrl(proxymWebhookUrl);
      setTimeout(() => setCopiedUrl(null), 2000);
    }
  }, [proxymWebhookUrl]);

  const handleUseSuggestedUrl = useCallback(() => {
    setForm((current) => ({ ...current, url: proxymWebhookUrl }));
  }, [proxymWebhookUrl, setForm]);

  const messageClass = message.kind === "success"
    ? "border-emerald-200 bg-emerald-50 text-emerald-700"
    : message.kind === "error"
      ? "border-red-200 bg-red-50 text-red-700"
      : "border-blue-200 bg-blue-50 text-blue-700";

  return (
    <div className="space-y-6">
      <Card
        title="Webhook integrations"
        badge={<StatusBadge ok={webhooks.length > 0} label={`${webhooks.length} configured`} />}
      >
        <div className="space-y-4">
          <p className="text-sm text-gray-500">
            Register GitHub, GitLab, or Jira webhooks to receive ticket status changes,
            manual updates, and LLM review comments.
          </p>

          {/* Your Webhook Endpoint Section */}
          <div className="rounded-lg border border-blue-200 bg-blue-50 p-4">
            <div className="flex items-center justify-between gap-4">
              <div className="min-w-0 flex-1">
                <h4 className="text-sm font-semibold text-blue-900">Your Proxym Webhook Endpoint</h4>
                <p className="mt-1 break-all font-mono text-sm text-blue-800">{proxymWebhookUrl}</p>
                <p className="mt-1 text-xs text-blue-600">
                  Copy this URL and paste it into your {form.system} webhook settings.
                </p>
              </div>
              <button
                type="button"
                onClick={handleCopyUrl}
                className="shrink-0 rounded-lg border border-blue-300 bg-white px-3 py-2 text-sm font-medium text-blue-700 transition-colors hover:bg-blue-100"
              >
                {copiedUrl === proxymWebhookUrl ? "✓ Copied!" : "Copy URL"}
              </button>
            </div>
          </div>

          <div className="grid gap-4 xl:grid-cols-[minmax(0,1.35fr)_minmax(280px,0.65fr)]">
            <form onSubmit={registerWebhook} className="space-y-3 rounded-lg border border-gray-200 p-4">
              <div className="grid gap-3 md:grid-cols-2">
                <label className="space-y-1 text-sm">
                  <span className="block text-xs font-medium uppercase tracking-wide text-gray-500">System</span>
                  <select
                    value={form.system}
                    onChange={(event) => setForm((current) => ({ ...current, system: event.target.value, url: "" }))}
                    className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900"
                  >
                    {SUPPORTED_WEBHOOK_SYSTEMS.map((system) => (
                      <option key={system.id} value={system.id}>{system.label}</option>
                    ))}
                  </select>
                </label>

                <label className="space-y-1 text-sm">
                  <span className="block text-xs font-medium uppercase tracking-wide text-gray-500">Webhook URL</span>
                  <input
                    value={form.url}
                    onChange={(event) => setForm((current) => ({ ...current, url: event.target.value }))}
                    placeholder={WEBHOOK_PLACEHOLDERS[form.system]}
                    className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900"
                  />
                </label>
              </div>

              {/* Suggested URL button */}
              <div className="flex items-center gap-2">
                <button
                  type="button"
                  onClick={handleUseSuggestedUrl}
                  className="text-xs text-blue-600 hover:text-blue-800 underline"
                >
                  Use suggested URL for {form.system}
                </button>
              </div>

              <div className="flex flex-wrap items-center gap-2">
                <button
                  type="submit"
                  disabled={savingSystem === form.system}
                  className="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-500 disabled:cursor-not-allowed disabled:bg-blue-300"
                >
                  {savingSystem === form.system ? "Saving…" : "Register webhook"}
                </button>
                <button
                  type="button"
                  onClick={() => setForm({ system: form.system, url: "" })}
                  className="rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50"
                >
                  Clear
                </button>
              </div>

              {/* Platform Setup Guide - Expandable */}
              <div className="mt-4 border-t border-gray-200 pt-4">
                <button
                  type="button"
                  onClick={() => setExpandedGuide(expandedGuide === form.system ? null : form.system)}
                  className="flex w-full items-center justify-between text-left"
                >
                  <span className="text-sm font-medium text-gray-700">
                    How to configure webhooks in {form.system}
                  </span>
                  <span className="text-gray-500">{expandedGuide === form.system ? "▲" : "▼"}</span>
                </button>

                {expandedGuide === form.system && (
                  <div className="mt-3 space-y-3 rounded-lg border border-gray-200 bg-gray-50 p-3">
                    <ol className="list-decimal space-y-1 pl-4 text-sm text-gray-600">
                      {guide.steps.map((step, idx) => (
                        <li key={idx}>{step}</li>
                      ))}
                    </ol>
                    <div className="flex flex-wrap gap-2 pt-2">
                      <a
                        href={guide.quickLink}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="rounded border border-gray-300 bg-white px-3 py-1 text-xs font-medium text-gray-700 hover:bg-gray-100"
                      >
                        Open {form.system} settings →
                      </a>
                      <a
                        href={guide.docsUrl}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="rounded border border-gray-300 bg-white px-3 py-1 text-xs font-medium text-gray-700 hover:bg-gray-100"
                      >
                        View {form.system} docs →
                      </a>
                    </div>
                  </div>
                )}
              </div>
            </form>

            <div className="rounded-lg border border-gray-200 bg-gray-50 p-4 text-sm text-gray-600">
              <h4 className="mb-2 text-sm font-semibold text-gray-900">What gets synced</h4>
              <ul className="space-y-2">
                <li>Ticket status transitions from the orchestrator.</li>
                <li>LLM-generated review comments and audit notes.</li>
                <li>Manual ticket edits that change workflow state.</li>
              </ul>
              <p className="mt-3 text-xs text-gray-500">
                Test payloads use the same shape as real events, so you can validate payload mapping before going live.
              </p>
            </div>
          </div>
        </div>
      </Card>

      {message.text && (
        <div className={`rounded-lg border px-4 py-3 text-sm ${messageClass}`} role="status">
          {message.text}
        </div>
      )}

      {/* One-Way Sync (API-based) Section */}
      <ExternalProviderPanel />

      <Card title="Registered webhooks">
        {loading ? (
          <div className="flex items-center gap-3 text-sm text-gray-500">
            <span className="inline-block h-4 w-4 animate-pulse rounded-full bg-blue-400"></span>
            Loading webhook registrations…
          </div>
        ) : webhooks.length === 0 ? (
          <div className="rounded-lg border border-dashed border-gray-200 bg-gray-50 p-4 text-sm text-gray-500">
            No webhooks registered yet. Add one above to mirror ticket changes into GitHub, GitLab, or Jira.
          </div>
        ) : (
          <div className="space-y-3">
            {webhooks.map((webhook) => {
              const meta = _systemMeta(webhook.system);
              const isBusy = savingSystem === webhook.system || testingSystem === webhook.system;
              const isJustTested = lastTestResult.system === webhook.system && lastTestResult.time;
              const testSuccess = lastTestResult.success;

              // Live status badge with pulse for active
              const isActive = webhook.status === "active";
              const statusBadge = isActive ? (
                <span className="inline-flex items-center gap-1.5 rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-medium text-emerald-700">
                  <span className="relative flex h-2 w-2">
                    <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-75"></span>
                    <span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-500"></span>
                  </span>
                  active
                </span>
              ) : (
                <StatusBadge ok={false} label={webhook.status || "unknown"} />
              );

              // Test result indicator
              const testIndicator = isJustTested ? (
                <span className={`ml-2 inline-flex items-center gap-1 text-xs ${testSuccess ? "text-emerald-600" : "text-red-600"}`}>
                  {testSuccess ? "✓ test passed" : "✗ test failed"}
                </span>
              ) : null;

              return (
                <div key={webhook.system} className="rounded-lg border border-gray-200 p-4">
                  <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
                    <div className="min-w-0 space-y-2">
                      <div className="flex flex-wrap items-center gap-2">
                        <h4 className="font-semibold text-gray-900">{meta.label}</h4>
                        {statusBadge}
                        {testIndicator}
                        {testingSystem === webhook.system && (
                          <span className="inline-flex items-center gap-1 text-xs text-blue-600">
                            <span className="inline-block h-3 w-3 animate-spin rounded-full border-2 border-blue-300 border-t-blue-600"></span>
                            testing…
                          </span>
                        )}
                      </div>
                      <p className="text-sm text-gray-500">{meta.description}</p>
                      <p className="break-all font-mono text-xs text-gray-600">{webhook.url}</p>
                      <div className="flex flex-wrap gap-3 text-xs text-gray-500">
                        <span>Registered: {_formatWebhookTime(webhook.created_at)}</span>
                        <span>Updated: {_formatWebhookTime(webhook.updated_at)}</span>
                      </div>
                    </div>

                    <div className="flex flex-wrap gap-2 lg:justify-end">
                      <button
                        type="button"
                        onClick={() => testWebhook(webhook.system, webhook.url)}
                        disabled={isBusy}
                        className="rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700 transition-colors hover:bg-blue-100 disabled:cursor-not-allowed disabled:opacity-60"
                      >
                        {testingSystem === webhook.system ? "Testing…" : "Test"}
                      </button>
                      <button
                        type="button"
                        onClick={() => deleteWebhook(webhook.system)}
                        disabled={isBusy}
                        className="rounded-lg border border-red-200 bg-red-50 px-3 py-1.5 text-xs font-medium text-red-700 transition-colors hover:bg-red-100 disabled:cursor-not-allowed disabled:opacity-60"
                      >
                        {savingSystem === webhook.system ? "Deleting…" : "Delete"}
                      </button>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </Card>
    </div>
  );
}

// ── External Provider (One-Way Sync) Panel ──────────────────

const EXTERNAL_PROVIDERS = [
  {
    id: "github",
    label: "GitHub",
    description: "Push tickets as GitHub issues. Manage repos via API.",
    icon: "GH",
    color: "bg-gray-900",
    keyLabel: "Personal Access Token",
    keyHelp: "https://github.com/settings/tokens",
    scopes: ["repo"],
    scopeHelp: "Required: 'repo' scope to create issues",
  },
  {
    id: "gitlab",
    label: "GitLab",
    description: "Push tickets as GitLab issues. Shell integration via glab.",
    icon: "GL",
    color: "bg-orange-500",
    keyLabel: "Personal/Project Access Token",
    keyHelp: "https://gitlab.com/-/profile/personal_access_tokens",
    scopes: ["api", "write_repository"],
    scopeHelp: "Required: 'api' or 'write_repository' scope",
  },
  {
    id: "jira",
    label: "Jira",
    description: "Push tickets as Jira issues. Manage projects via API.",
    icon: "JI",
    color: "bg-blue-600",
    keyLabel: "API Token",
    keyHelp: "https://id.atlassian.com/manage-profile/security/api-tokens",
    needsEmail: true,
    scopes: ["write:issue:jira"],
    scopeHelp: "Required: 'write:issue:jira' scope + your email",
  },
];

function useExternalProviders() {
  const [providers, setProviders] = useState([]);
  const [loading, setLoading] = useState(false);
  const [configForm, setConfigForm] = useState({
    provider: "github",
    apiKey: "",
    baseUrl: "",
    email: "",
    name: "default",
  });
  const [showForm, setShowForm] = useState(false);
  const [message, setMessage] = useState({ kind: "", text: "" });

  const refresh = useCallback(async () => {
    setLoading(true);
    try {
      const data = await get("/external/providers");
      setProviders(Array.isArray(data) ? data : []);
    } catch (err) {
      setMessage({ kind: "error", text: "Failed to load providers" });
    } finally {
      setLoading(false);
    }
  }, []);

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

  const configureProvider = useCallback(async () => {
    const { provider, apiKey, baseUrl, email, name } = configForm;
    if (!apiKey) {
      setMessage({ kind: "error", text: "API key is required" });
      return;
    }

    setLoading(true);
    setMessage({ kind: "info", text: "Saving and testing configuration..." });

    try {
      const payload = { api_key: apiKey, name };
      if (baseUrl) payload.base_url = baseUrl;
      if (email) payload.email = email;

      const response = await post(`/external/providers/${provider}`, payload);
      
      // Handle HTTP error responses
      if (!response) {
        throw new Error("No response from server");
      }
      
      if (response.ok === false) {
        const errorDetail = response.body?.detail || response.body?.message || "Failed to configure";
        throw new Error(errorDetail);
      }

      // Show test result from the response
      const testSuccess = response?.test_success;
      const testMessage = response?.test_message || "Configuration saved";

      if (testSuccess) {
        setMessage({ kind: "success", text: `✓ ${provider} configured and verified: ${testMessage}` });
      } else {
        setMessage({
          kind: "error",
          text: `${provider} saved but test failed: ${testMessage}. Check your token and scopes.`,
        });
      }

      setConfigForm((c) => ({ ...c, apiKey: "" }));
      setShowForm(false);
      await refresh();
    } catch (err) {
      console.error("Configure provider error:", err);
      setMessage({ 
        kind: "error", 
        text: err?.message || "Configuration failed. Check server logs for details." 
      });
    } finally {
      setLoading(false);
    }
  }, [configForm, refresh]);

  const removeProvider = useCallback(async (provider, name) => {
    if (!confirm(`Remove ${provider}:${name} configuration?`)) return;

    setLoading(true);
    try {
      await del(`/external/providers/${provider}?name=${encodeURIComponent(name)}`);
      setMessage({ kind: "success", text: `${provider}:${name} removed` });
      await refresh();
    } catch (err) {
      setMessage({ kind: "error", text: "Failed to remove provider" });
    } finally {
      setLoading(false);
    }
  }, [refresh]);

  const testProvider = useCallback(async (provider, name) => {
    setLoading(true);
    try {
      const response = await post(`/external/providers/${provider}/test?name=${encodeURIComponent(name)}`, {});
      if (response && response.ok === false) {
        throw new Error(response.body?.detail || "Test failed");
      }
      setMessage({
        kind: response?.success ? "success" : "error",
        text: response?.message || "Test complete",
      });
    } catch (err) {
      setMessage({ kind: "error", text: err?.message || "Test failed" });
    } finally {
      setLoading(false);
    }
  }, []);

  return {
    providers,
    loading,
    configForm,
    setConfigForm,
    showForm,
    setShowForm,
    message,
    setMessage,
    refresh,
    configureProvider,
    removeProvider,
    testProvider,
  };
}

function ExternalProviderPanel() {
  const {
    providers,
    loading,
    configForm,
    setConfigForm,
    showForm,
    setShowForm,
    message,
    setMessage,
    configureProvider,
    removeProvider,
    testProvider,
  } = useExternalProviders();

  const activeProviders = providers.filter((p) => p.has_key);
  const selectedProvider = EXTERNAL_PROVIDERS.find((p) => p.id === configForm.provider);

  const messageClass =
    message.kind === "success"
      ? "border-emerald-200 bg-emerald-50 text-emerald-700"
      : message.kind === "error"
        ? "border-red-200 bg-red-50 text-red-700"
        : "border-blue-200 bg-blue-50 text-blue-700";

  return (
    <Card
      title="One-way sync (API-based)"
      badge={
        <StatusBadge
          ok={activeProviders.length > 0}
          label={`${activeProviders.length} configured`}
        />
      }
    >
      <div className="space-y-4">
        <p className="text-sm text-gray-500">
          Configure API access to push tickets as issues directly to GitHub, GitLab, or Jira.
          No webhooks required—works from CLI and dashboard.
        </p>

        {message.text && (
          <div className={`rounded-lg border px-4 py-3 text-sm ${messageClass}`}>
            {message.text}
          </div>
        )}

        {/* Provider Cards */}
        <div className="grid gap-3 sm:grid-cols-3">
          {EXTERNAL_PROVIDERS.map((provider) => {
            const config = providers.find(
              (p) => p.provider === provider.id && p.has_key
            );
            const isConfigured = !!config;

            return (
              <div
                key={provider.id}
                className={`rounded-lg border p-4 ${
                  isConfigured
                    ? "border-emerald-200 bg-emerald-50"
                    : "border-gray-200 bg-white"
                }`}
              >
                <div className="flex items-start justify-between">
                  <div className="flex items-center gap-2">
                    <span
                      className={`flex h-8 w-8 items-center justify-center rounded-md text-xs font-bold text-white ${provider.color}`}
                    >
                      {provider.icon}
                    </span>
                    <div>
                      <h4 className="font-semibold text-gray-900">{provider.label}</h4>
                      {isConfigured ? (
                        <span className="text-xs text-emerald-600">● Connected</span>
                      ) : (
                        <span className="text-xs text-gray-400">○ Not configured</span>
                      )}
                    </div>
                  </div>
                </div>
                <p className="mt-2 text-xs text-gray-500">{provider.description}</p>

                <div className="mt-3 flex gap-2">
                  {isConfigured ? (
                    <>
                      <button
                        onClick={() => testProvider(provider.id, config.name)}
                        disabled={loading}
                        className="rounded border border-gray-300 bg-white px-2 py-1 text-xs font-medium text-gray-700 hover:bg-gray-50"
                      >
                        Test
                      </button>
                      <button
                        onClick={() => removeProvider(provider.id, config.name)}
                        disabled={loading}
                        className="rounded border border-red-200 bg-red-50 px-2 py-1 text-xs font-medium text-red-700 hover:bg-red-100"
                      >
                        Remove
                      </button>
                    </>
                  ) : (
                    <button
                      onClick={() => {
                        setConfigForm((c) => ({ ...c, provider: provider.id }));
                        setShowForm(true);
                        setMessage({ kind: "", text: "" });
                      }}
                      className="rounded bg-blue-600 px-3 py-1 text-xs font-medium text-white hover:bg-blue-500"
                    >
                      Configure
                    </button>
                  )}
                </div>
              </div>
            );
          })}
        </div>

        {/* Configuration Form */}
        {showForm && (
          <div className="rounded-lg border border-gray-200 bg-gray-50 p-4">
            <h4 className="mb-3 font-semibold text-gray-900">
              Configure {selectedProvider?.label}
            </h4>
            <div className="grid gap-3">
              <div className="grid gap-3 md:grid-cols-2">
                <label className="space-y-1 text-sm">
                  <span className="block text-xs font-medium uppercase tracking-wide text-gray-500">
                    {selectedProvider?.keyLabel || "API Key"}
                  </span>
                  <input
                    type="password"
                    value={configForm.apiKey}
                    onChange={(e) =>
                      setConfigForm((c) => ({ ...c, apiKey: e.target.value }))
                    }
                    placeholder="••••••••••••••••"
                    className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900"
                  />
                  {selectedProvider?.keyHelp && (
                    <div className="text-xs text-gray-500">
                      <a
                        href={selectedProvider.keyHelp}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="text-blue-600 hover:underline"
                      >
                        Get your token →
                      </a>
                      {selectedProvider.scopeHelp && (
                        <p className="mt-1 text-amber-600">{selectedProvider.scopeHelp}</p>
                      )}
                    </div>
                  )}
                </label>

                <label className="space-y-1 text-sm">
                  <span className="block text-xs font-medium uppercase tracking-wide text-gray-500">
                    Config Name
                  </span>
                  <input
                    value={configForm.name}
                    onChange={(e) =>
                      setConfigForm((c) => ({ ...c, name: e.target.value }))
                    }
                    placeholder="default"
                    className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900"
                  />
                  <span className="text-xs text-gray-400">For multiple accounts</span>
                </label>
              </div>

              {selectedProvider?.id === "gitlab" && (
                <label className="space-y-1 text-sm">
                  <span className="block text-xs font-medium uppercase tracking-wide text-gray-500">
                    Base URL (optional)
                  </span>
                  <input
                    value={configForm.baseUrl}
                    onChange={(e) =>
                      setConfigForm((c) => ({ ...c, baseUrl: e.target.value }))
                    }
                    placeholder="https://gitlab.com/api/v4 (default)"
                    className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900"
                  />
                  <span className="text-xs text-gray-400">For self-hosted GitLab only</span>
                </label>
              )}

              {selectedProvider?.needsEmail && (
                <label className="space-y-1 text-sm">
                  <span className="block text-xs font-medium uppercase tracking-wide text-gray-500">
                    Email
                  </span>
                  <input
                    type="email"
                    value={configForm.email}
                    onChange={(e) =>
                      setConfigForm((c) => ({ ...c, email: e.target.value }))
                    }
                    placeholder="user@example.com"
                    className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900"
                  />
                </label>
              )}

              <div className="flex gap-2 pt-2">
                <button
                  onClick={configureProvider}
                  disabled={loading || !configForm.apiKey}
                  className="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-500 disabled:bg-blue-300"
                >
                  {loading ? "Saving…" : "Save Configuration"}
                </button>
                <button
                  onClick={() => setShowForm(false)}
                  className="rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
                >
                  Cancel
                </button>
              </div>
            </div>
          </div>
        )}

        {/* CLI Hint */}
        <div className="rounded-lg border border-gray-200 bg-gray-50 p-3 text-xs text-gray-500">
          <strong>CLI commands:</strong>
          <code className="mx-1 rounded bg-gray-200 px-1 py-0.5">proxym external configure github --api-key &lt;token&gt;</code>
          <code className="mx-1 rounded bg-gray-200 px-1 py-0.5">proxym external project list github</code>
          <code className="mx-1 rounded bg-gray-200 px-1 py-0.5">proxym external issue sync TKT-123 github</code>
        </div>
      </div>
    </Card>
  );
}
