import type { ExtendedHumanInterventionConfig } from '@/types/index';

export interface LobeChatPluginApi {
  /**
   * Default execution timeout in milliseconds for this API.
   * Falls back to the global default (120_000 ms) when omitted.
   * The resolver reads this when the LLM does not supply `arguments.timeout`.
   */
  defaultTimeoutMs?: number;
  description: string;
  /**
   * Human intervention configuration
   * Controls when and how the tool requires human approval/selection
   *
   * Can be either:
   * - Simple: A policy string ('never', 'always', 'first')
   * - Complex: Array of rules for parameter-level control
   *
   * Examples:
   * - 'always' - always require intervention
   * - [{ match: { command: "git add:*" }, policy: "never" }, { policy: "always" }]
   */
  humanIntervention?: ExtendedHumanInterventionConfig;
  name: string;
  parameters: Record<string, any>;
  url?: string;
}

export interface LobeToolManifest {
  api: LobeChatPluginApi[];
  identifier: string;
  meta: any;
  systemRole?: string;
  type?: 'default' | 'standalone' | 'markdown' | 'mcp' | 'builtin';
}

/**
 * Tools generation context
 */
export interface ToolsGenerationContext {
  /** Additional extension context */
  [key: string]: any;
  /** Whether image generation is allowed */
  allowImageGeneration?: boolean;
  /** Environment information */
  environment?: 'desktop' | 'web';
  /** Whether search is enabled */
  isSearchEnabled?: boolean;
  /** Model name for context-aware plugin filtering */
  model?: string;
  /** Provider name for context-aware plugin filtering */
  provider?: string;
}

/**
 * Plugin enable checker function
 */
export type PluginEnableChecker = (params: {
  context?: ToolsGenerationContext;
  manifest: LobeToolManifest;
  model: string;
  pluginId: string;
  provider: string;
}) => boolean;

/**
 * Function calling support checker function
 */
export type FunctionCallChecker = (model: string, provider: string) => boolean;

/**
 * Tools generation parameters
 */
export interface GenerateToolsParams {
  /** Additional context information */
  context?: ToolsGenerationContext;
  /**
   * Tool IDs to exclude from the default tools list.
   * These IDs will be filtered out from defaultToolIds before merging.
   * Useful for manual skill mode where only discovery tools should be excluded.
   */
  excludeDefaultToolIds?: string[];
  /** Model name */
  model: string;
  /** Provider name */
  provider: string;
  /**
   * Whether to skip merging default tools.
   * When true, only the explicitly provided toolIds will be used.
   * Useful for broadcast scenarios where tools should be completely disabled.
   */
  skipDefaultTools?: boolean;
  /** List of tool IDs to enable */
  toolIds?: string[];
}

/**
 * Tool name generator function
 */
export type ToolNameGenerator = (identifier: string, apiName: string, type?: string) => string;

/**
 * ToolsEngine configuration options
 */
export interface ToolsEngineOptions {
  /** Default tool IDs that will always be added to the end of the tools list */
  defaultToolIds?: string[];
  /** Optional plugin enable checker function */
  enableChecker?: PluginEnableChecker;
  /** Optional function calling support checker function */
  functionCallChecker?: FunctionCallChecker;
  /** Optional tool name generator function */
  generateToolName?: ToolNameGenerator;
  /** Statically injected manifest schemas */
  manifestSchemas: LobeToolManifest[];
}

/**
 * Tools generation result
 */
export interface ToolsGenerationResult {
  /** List of enabled manifests with systemRole and other metadata */
  enabledManifests: LobeToolManifest[];
  /** List of enabled tool IDs */
  enabledToolIds: string[];
  /** Filtered plugins and their reasons */
  filteredTools: Array<{
    id: string;
    reason: 'not_found' | 'disabled' | 'incompatible';
  }>;
  /** Generated tools array */
  tools?: UniformTool[];
}

export interface UniformFunctions {
  /**
   * The description of what the function does.
   * @type {string}
   * @memberof UniformFunctions
   */
  description?: string;
  /**
   * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
   * @type {string}
   * @memberof UniformFunctions
   */
  name: string;
  /**
   * The parameters the functions accepts, described as a JSON Schema object. See the [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for documentation about the format.
   * @type {{ [key: string]: any }}
   * @memberof UniformFunctions
   */
  parameters?: {
    [key: string]: any;
  };
}

export interface UniformTool {
  function: UniformFunctions;

  /**
   * The type of the tool. Currently, only `function` is supported.
   */
  type: 'function';
}

// ---- Tool Lifecycle Types ----

export type ToolSource = 'builtin' | 'client' | 'mcp' | 'klavis' | 'lobehubSkill';

/**
 * Where the tool is executed for a given invocation.
 * Orthogonal to ToolSource (origin): executor describes dispatch target.
 */
export type ToolExecutor = 'client' | 'server';

/**
 * How a tool was activated at step level
 */
export type ActivationSource = 'active_tools' | 'mention' | 'device' | 'discovery';

/**
 * Operation-level tool set: determined at createOperation time, immutable during execution.
 */
export interface OperationToolSet {
  enabledToolIds: string[];
  executorMap?: Record<string, ToolExecutor>;
  manifestMap: Record<string, LobeToolManifest>;
  sourceMap: Record<string, ToolSource>;
  tools: UniformTool[];
}

/**
 * Record of a tool activated at step level.
 */
export interface ActivatedStepTool {
  activatedAtStep: number;
  id: string;
  manifest?: LobeToolManifest;
  source: ActivationSource;
}

/**
 * Declarative delta describing tool changes for a single step.
 * Built by `buildStepToolDelta`, consumed by `ToolResolver.resolve`.
 */
export interface StepToolDelta {
  activatedTools: Array<{
    id: string;
    manifest?: LobeToolManifest;
    source: ActivationSource;
  }>;
  deactivatedToolIds?: string[];
}

/**
 * Final resolved tool set ready for LLM call.
 */
export interface ResolvedToolSet {
  enabledToolIds: string[];
  executorMap?: Record<string, ToolExecutor>;
  manifestMap: Record<string, LobeToolManifest>;
  sourceMap: Record<string, ToolSource>;
  tools: UniformTool[];
}
