/**
 * Connector Types — independent of the plugin (pipeline-node) subsystem.
 *
 * Connectors expose tools to Forge chat and the browser extension.
 * Manifests live in <dataDir>/connectors/<id>/manifest.yaml, fetched
 * from the remote `forge-connectors` registry. There are no built-in
 * connectors — first launch requires a successful registry sync (which
 * is cached afterwards for offline use).
 *
 * See lib/help-docs/17-connectors.md for the user-facing manifest spec.
 */

/** Where a connector's scripts run inside the extension. */
export type ConnectorRunner = 'main' | 'isolated';

/** Where a tool's execution lives. */
export type ConnectorProtocol = 'browser' | 'http' | 'shell';

/** Schema for one settings or parameter field. */
export interface ConnectorFieldSchema {
  type: 'string' | 'number' | 'boolean' | 'secret' | 'json' | 'select';
  label?: string;
  description?: string;
  required?: boolean;
  default?: unknown;
  /** select-type options */
  options?: string[];
}

/**
 * Server-side HTTP request shape, used by `protocol: http` tools.
 * Template tokens {base_url}, {settings.*}, {args.*} are expanded at run time.
 */
export interface HttpRequestSpec {
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD';
  /** Full URL. Templated. */
  url: string;
  /** Header values are templated. */
  headers?: Record<string, string>;
  /** Query params. Values templated. Appended after any existing ? on url. */
  query?: Record<string, string>;
  /** Body. string = sent as-is (templated); object = JSON.stringify'd (string values templated). */
  body?: string | Record<string, unknown>;
}

/**
 * Where the extension's generic runner should land the active tab before
 * executing a tool's script.
 */
export interface ConnectorPage {
  /** Template URL; supports {base_url}, {settings.*}, {args.*}. */
  url: string;
  /**
   * Substring; if the current tab URL already contains it, skip
   * navigation. Templated values are expanded the same way as `url`
   * (settings server-side, args at runtime). Omit to always navigate.
   */
  on_target?: string;
}

/**
 * A single callable a connector exposes to the LLM.
 *
 * For `protocol: 'browser'` the script body runs in the user's tab via
 * chrome.scripting.executeScript (page context, has document/fetch/etc,
 * no chrome.* APIs). The extension is a generic runner — it doesn't
 * know about specific connectors. Adding a new connector means writing
 * a manifest with `page` + `script` per tool; no extension rebuild.
 */
export interface ConnectorTool {
  description: string;
  parameters?: Record<string, ConnectorFieldSchema>;
  /** Requires user confirmation before invoking (e.g. add_comment, close_issue). */
  destructive?: boolean;
  /** Free-form description of the return shape — surfaced to the LLM. */
  returns?: string;

  /** Where this tool runs. Default 'browser'. */
  protocol?: ConnectorProtocol;

  // ── protocol: 'browser' ───────────────────────────────────
  /** Page to navigate to before running the script. */
  page?: ConnectorPage;
  /**
   * JavaScript function body. Receives `args` (the LLM's parsed
   * parameters). Returns a JSON-serializable value. Runs in the user's
   * tab — must be self-contained (no closures over Forge/extension code).
   */
  script?: string;

  // ── protocol: 'http' ──────────────────────────────────────
  /** Request shape. Templates {base_url}, {settings.*}, {args.*}. */
  request?: HttpRequestSpec;

  // ── protocol: 'shell' ─────────────────────────────────────
  /** Command + args (each templated independently — no shell injection). */
  command?: string[];
  /** Working directory (templated). */
  cwd?: string;
  /** Extra env vars (values templated). */
  env?: Record<string, string>;

  /** shell/http: timeout in milliseconds. Default 30000, max 300000. */
  timeout_ms?: number;
}

/**
 * One adapter inside a connector. Most connectors are 1:1 (single tool
 * set, single auth) — the manifest's top-level `tools`/`settings`/
 * `host_match` fields define that single entry. Use `connectors[]`
 * only when one auth covers multiple sibling adapters (Atlassian,
 * Google Workspace, M365).
 */
export interface ConnectorEntry {
  id: string;
  host_permissions?: string[];
  tools: Record<string, ConnectorTool>;
  /** Per-user settings (host URL, default project, etc.). */
  settings?: Record<string, ConnectorFieldSchema>;
  /**
   * Chrome match pattern. Runner uses this to find/open authenticated
   * tabs for this connector. Supports {base_url}, {settings.*}.
   */
  host_match?: string;
  /**
   * Substring. If the tab URL contains this after navigation, treat as
   * "user not logged in" and abort with loginRequired: true.
   */
  login_redirect?: string;
  /** Inherits from ConnectorDefinition.runner if unset. */
  runner?: ConnectorRunner;
}

/**
 * Optional reachability probe shipped inside a connector manifest.
 * Used by the Settings → Connectors "Test" button — the UI hits
 * `POST /api/connectors/<id>/test`, which dispatches to one of:
 *
 *   probe: 'http' (default)  — server issues a one-shot HTTP request
 *                              with {settings.*} expanded. Use this
 *                              when the service has a clean REST
 *                              endpoint (`/api/v4/user`, `/rate_limit`).
 *
 *   probe: 'browser'         — forwarded to the browser extension via
 *                              the bridge. Extension acquires/opens a
 *                              tab matching `host_match`, navigates,
 *                              and checks the resulting URL against
 *                              `login_redirect`. Verifies the user is
 *                              actually logged in (cookie-based auth)
 *                              — no server-side credentials involved.
 */
export interface ConnectorTest {
  /** Human-readable hint shown next to the Test button. */
  description?: string;

  /**
   * Probe kind. Default 'http'. Browser probes require an installed +
   * paired Forge browser extension.
   */
  probe?: 'http' | 'browser';

  // ── probe: 'http' ────────────────────────────────────────
  /** HTTP request to issue. Same template tokens as a tool request. */
  request?: HttpRequestSpec;
  /**
   * Status codes that count as success. Default [200].
   * (Some APIs return 204 for a successful auth check.)
   */
  ok_status?: number[];
  /**
   * Template for the success message. Tokens `{{<json-path>}}` against
   * the parsed response body. Empty → "OK (HTTP <status>)".
   * Example: "Authenticated as {{username}} ({{name}})".
   */
  ok_template?: string;

  // ── probe: 'browser' ─────────────────────────────────────
  // No fields required — the extension reuses the connector's
  // top-level host_match + login_redirect (1:1) or the first entry's
  // (1:N) to find the tab and detect login redirects.

  /** Override the default timeout (http: 15s, browser: 30s). */
  timeout_ms?: number;
}

/**
 * The on-disk manifest for a connector, loaded from
 * `<dataDir>/connectors/<id>/manifest.yaml`.
 */
export interface ConnectorDefinition {
  id: string;
  name: string;
  version: string;
  /** Emoji or short string for UI badges. */
  icon?: string;
  author?: string;
  description?: string;

  /**
   * Minimum Forge version this manifest expects. The registry filter
   * hides newer-than-supported manifests so users on older Forge
   * versions don't try to install something that depends on newer APIs.
   */
  min_forge_version?: string;

  /**
   * Which extension execution context runs the connector's scripts.
   * Default 'main' (permissive-CSP sites). Use 'isolated' for strict
   * CSP sites (Teams, github.com). Per-connector, not per-tool — a
   * host has one CSP profile.
   */
  runner?: ConnectorRunner;

  // ─── 1:1 connector — top-level fields ──────────────────
  /** Most connectors expose tools directly here. */
  tools?: Record<string, ConnectorTool>;
  settings?: Record<string, ConnectorFieldSchema>;
  host_match?: string;
  login_redirect?: string;

  // ─── 1:N suite — list of sibling entries sharing auth ──
  connectors?: ConnectorEntry[];

  /** Optional reachability probe — wired to the Settings "Test" button. */
  test?: ConnectorTest;
}

/**
 * A reference to a connector definition without its tools/scripts —
 * used by the marketplace listing so we don't pay the YAML parse cost
 * for connectors the user hasn't installed.
 */
export interface ConnectorMarketEntry {
  id: string;
  name: string;
  version: string;
  icon?: string;
  description?: string;
  author?: string;
  /** present if locally installed */
  installed_version?: string;
  /** true when registry has a newer version than installed_version */
  update_available?: boolean;
  /** true when min_forge_version is satisfied */
  compatible: boolean;
  /**
   * Where this entry originates:
   *   'registry' — listed in the remote registry (may also be installed)
   *   'local'    — installed via /api/connectors/install-local, no
   *                registry counterpart (no Update path)
   */
  source: 'registry' | 'local';
}
