import type { z } from 'zod';
import type { Sql } from '../../db.js';

/**
 * Unified permission ladder for native BooCode inference. Gates the write tools:
 *   plan   — read-only: create/edit/delete are denied (no staging).
 *   ask    — stage to the pending-changes queue; `apply_pending` is denied so the
 *            agent cannot self-apply (the human approves via the Diff panel).
 *   bypass — apply each write immediately (no queue, no approval).
 * Undefined preserves the historical behavior (stage + `apply_pending` allowed).
 */
export type PermissionMode = 'plan' | 'ask' | 'bypass';

/** Narrow a raw task/request mode id to a unified PermissionMode, else undefined
 *  (e.g. an external agent's native mode id, or null). */
export function asPermissionMode(id: string | null | undefined): PermissionMode | undefined {
  return id === 'plan' || id === 'ask' || id === 'bypass' ? id : undefined;
}

export interface ToolJsonSchema {
  type: 'function';
  function: {
    name: string;
    description: string;
    parameters: Record<string, unknown>;
  };
}

/**
 * Context passed to BooCoder tool execute functions.
 *
 * Unlike BooChat's tools (which only need projectRoot), BooCoder's write tools
 * interact with the database (pending_changes table) and need session/task
 * context for proper attribution.
 */
export interface ToolContext {
  sql: Sql;
  sessionId: string;
  taskId: string | null;
  /** Native-BooCode permission gate for write tools (undefined = legacy behavior). */
  permissionMode?: PermissionMode;
}

export interface ToolDef<TInput> {
  name: string;
  description: string;
  inputSchema: z.ZodType<TInput>;
  jsonSchema: ToolJsonSchema;
  execute(input: TInput, projectRoot: string, context: ToolContext): Promise<unknown>;
}
