// HostBridge —— surface 宿主能力抽象层
//
// Web 走浏览器 API / Electron 走 Node / iOS 走 Swift / Android 走 Kotlin。
// 任何业务代码访问"宿主能力"必须经此接口，不允许直接 import browser/Node API。
//
// 详见 docs/modules/agent/02-architecture.md §1.1.1 / §1.3.2。

// ───────────────────────────────────────────────────────────
// Capability 协商（§1.3.2）
// ───────────────────────────────────────────────────────────

/**
 * 宿主能力枚举 —— 启动时由 HostBridge 上报，后端 ToolRegistry 用 availabilityExpression
 * 过滤 client: 工具。Web 端默认空集，所有 client: 工具自动不可见。
 *
 * 命名约定：`<域>.<动作>`。新增能力时同步更新 docs/modules/agent/02-architecture.md §1.3.2。
 */
export type HostCapability =
  | "fs.read"
  | "fs.write"
  | "fs.list"
  | "clipboard.read"
  | "clipboard.write"
  | "notify"
  | "shell.exec"
  | "shell.openExternal";

/** 工具调用结果（§1.3.2 invoke 返回结构）。`granted=false` = 用户拒绝授权 */
export interface HostInvokeResult<T = unknown> {
  readonly granted: boolean;
  readonly result?: T;
  readonly error?: string;
}

/** Capability 协商消息：client → server，建连后首条上报 */
export interface CapabilityNegotiationMessage {
  readonly type: "capability.negotiation";
  readonly surface: HostSurface;
  readonly capabilities: readonly HostCapability[];
  readonly protocolVersion: string;
}

/**
 * HostBridge 上报的 surface 细分类型 —— 注意与 backend `ListToolsContext.surface`
 * （`'web' | 'desktop' | 'mobile' | 'teams' | 'cli'`）**故意分两层**：
 * - 此处 protocol 层：客户端壳告诉协议自己是什么——Electron 与未来其他 desktop runtime
 *   要区分（`desktop-electron` / `desktop-tauri` 等）。
 * - backend ListToolsContext：业务过滤层，按"形态类"分组（desktop 不细分 runtime）。
 *
 * 上报值 → backend 形态映射在 Gateway Controller 做（Phase 2 后续 PR 落地）。
 */
export type HostSurface = "web" | "desktop-electron" | "cli" | "teams" | "ios" | "android";

// ───────────────────────────────────────────────────────────
// 类型化 API（向后兼容 PR0.5 骨架；本地代码可直接调）
// ───────────────────────────────────────────────────────────

export interface HostBridgeFileAPI {
  /** 交互式弹文件选择器（用户主动） */
  pickFile(opts?: { accept?: string[]; multiple?: boolean }): Promise<HostBridgeFileRef[]>;
  readFile(ref: HostBridgeFileRef): Promise<Uint8Array>;
  /** 路径式读（PR12 File.read，受 scope 约束，首次需 OS 授权） */
  readPath(path: string): Promise<Uint8Array>;
  /** 路径式写（PR12 File.write，受 scope 约束） */
  writePath(path: string, data: Uint8Array): Promise<void>;
  /** 路径式列目录（PR12 File.list） */
  list(dir: string): Promise<HostBridgeDirEntry[]>;
}

export interface HostBridgeFileRef {
  readonly id: string;
  readonly name: string;
  readonly size: number;
  readonly mime: string;
}

export interface HostBridgeDirEntry {
  readonly name: string;
  readonly path: string;
  readonly type: "file" | "directory" | "symlink";
  readonly size?: number;
}

export interface HostBridgeClipboardAPI {
  readText(): Promise<string>;
  writeText(text: string): Promise<void>;
}

export interface HostBridgeNotificationAPI {
  show(opts: { title: string; body?: string }): Promise<void>;
}

export interface HostBridgeShellAPI {
  openExternal(url: string): Promise<void>;
  /** PR13 Shell.exec：必须走 OS 沙盒，解释器白名单 + network egress 默认禁 */
  exec(cmd: string, args: readonly string[], opts?: HostBridgeExecOpts): Promise<HostBridgeExecResult>;
}

export interface HostBridgeExecOpts {
  readonly cwd?: string;
  readonly timeoutMs?: number;
  readonly env?: Readonly<Record<string, string>>;
  readonly stdin?: string;
}

export interface HostBridgeExecResult {
  readonly exitCode: number;
  readonly stdout: string;
  readonly stderr: string;
  readonly timedOut: boolean;
}

// ───────────────────────────────────────────────────────────
// HostBridge 顶层接口
// ───────────────────────────────────────────────────────────

export interface HostBridge {
  readonly surface: HostSurface;
  readonly file: HostBridgeFileAPI;
  readonly clipboard: HostBridgeClipboardAPI;
  readonly notification: HostBridgeNotificationAPI;
  readonly shell: HostBridgeShellAPI;

  /** 启动时上报当前 surface 支持的能力集（§1.3.2） */
  capabilities(): readonly HostCapability[];

  /**
   * 后端 tool_use → 前端动态分发入口（§1.3.2）。
   * tool name 例：`client:fs.read` / `client:clipboard.write` / `client:shell`。
   * 实现要点：① 校验能力在 capabilities() 内；② 首次调用必须 OS 授权弹窗；③ 上报 TrajectoryEvent audit。
   */
  invoke<T = unknown>(tool: string, args: unknown): Promise<HostInvokeResult<T>>;
}

/** 默认 Web surface 的能力集（空集，仅暴露 shell.openExternal）—— Web 端兜底实现可复用 */
export const WEB_DEFAULT_CAPABILITIES: readonly HostCapability[] = ["shell.openExternal"] as const;

/**
 * Desktop Electron 的能力集。
 *
 * **常量同步面**（PR15.5 monorepo workspace 落地前必有 3 处镜像）：
 * - 此处（protocol 事实源）
 * - `desktop/src/main.ts` 同名局部常量（ESM/CJS 桥接 workaround，详见 main.ts 注释 + .learnings）
 * - `backend/src/modules/agent/tools/host-capability.types.ts` 的 `SURFACE_DEFAULT_CAPABILITIES.desktop`
 * 新增 / 修改 capability **三处全改**——单点漂移会让能力静默不可见或越权。
 */
export const DESKTOP_ELECTRON_CAPABILITIES: readonly HostCapability[] = [
  "fs.read",
  "fs.write",
  "fs.list",
  "clipboard.read",
  "clipboard.write",
  "notify",
  "shell.exec",
  "shell.openExternal",
] as const;
