import type { AIBuiltinToolInfo } from './aiBuiltinToolInfo.types';

export interface AIBuiltinToolFlow {
  title: string;
  steps: string;
  description: string;
}

export interface AIBuiltinToolParameterHint {
  name: string;
  required: boolean;
  typeLabel: string;
  description: string;
  enumValues: string[];
  defaultValue: string;
  exampleValue: string;
}

export const BUILTIN_TOOL_FLOWS: AIBuiltinToolFlow[] = [
  {
    title: '定位表与字段',
    steps: 'get_connections -> get_databases -> get_tables -> get_columns',
    description: '适合先找连接、找库、找表，再确认真实字段名后生成 SQL。',
  },
  {
    title: '字段反查表',
    steps: 'get_databases -> get_all_columns',
    description: '适合只知道字段名、业务含义或注释关键词，但还不确定具体落在哪张表。',
  },
  {
    title: '结构深挖',
    steps: 'get_columns -> get_indexes -> get_foreign_keys -> get_triggers -> get_table_ddl',
    description: '适合做索引优化、关系梳理、隐式副作用排查和 DDL 审查。',
  },
  {
    title: '一键结构快照',
    steps: 'inspect_table_bundle',
    description: '适合一次带回字段、索引、外键、触发器和 DDL；必要时还能附带样例行，减少来回调用。',
  },
  {
    title: '全库快速摸底',
    steps: 'inspect_database_bundle -> inspect_table_bundle',
    description: '适合先看整库有哪些表、每张表大概有哪些字段，再对目标表继续做深挖快照。',
  },
  {
    title: 'AI 应用健康总览',
    steps: 'inspect_app_health -> inspect_ai_setup_health / inspect_app_logs / inspect_recent_connection_failures / inspect_ai_last_render_error / inspect_ai_message_flow',
    description: '适合用户反馈 AI 不稳定、连接和 MCP 问题交织、回复气泡显示异常，或需要先看整体健康状态时，一次汇总配置、日志、连接失败、渲染异常、消息流和工作区现场。',
  },
  {
    title: '导出 AI 排障支持包',
    steps: 'inspect_ai_support_bundle -> inspect_app_health / inspect_ai_context_budget / inspect_ai_message_flow / inspect_mcp_remote_access',
    description: '适合需要一次性带走排障证据，或用户反馈 AI 不成熟、不稳定、MCP/连接/日志/上下文都可能相关时，先生成不含密钥和数据库密码的支持包。',
  },
  {
    title: '选择 AI 工具路线',
    steps: 'inspect_ai_tool_catalog -> inspect_ai_runtime / inspect_mcp_setup',
    description: '适合先按关键词确认该用哪些内置探针、每个工具 arguments 怎么填，以及当前有没有外部 MCP 工具可用。',
  },
  {
    title: '一键体检 AI 配置',
    steps: 'inspect_ai_setup_health -> inspect_ai_providers / inspect_mcp_setup / inspect_ai_guidance',
    description: '适合先拿到一份 AI 配置健康快照，看清当前是供应商没配好、聊天发送前置没满足、MCP 没接入，还是提示词 / Skills / 上下文还不完整，再决定往哪条探针继续下钻。',
  },
  {
    title: '查看 AI 当前能力',
    steps: 'inspect_ai_runtime -> inspect_ai_context / inspect_current_connection',
    description: '适合先确认当前模型、安全级别、上下文级别、Skills 和 MCP 工具，再决定让 AI 走哪条探针链路。',
  },
  {
    title: '核对写入安全边界',
    steps: 'inspect_ai_safety -> inspect_ai_runtime -> inspect_current_connection',
    description: '适合先确认当前是不是只读、DDL/DML 到底允不允许、MCP 写操作是否还需要 allowMutating，再决定后续该走查询、改数据还是改结构。',
  },
  {
    title: '排查供应商与模型',
    steps: 'inspect_ai_providers -> inspect_ai_runtime',
    description: '适合先确认当前到底配置了哪些供应商、哪个在生效、有没有缺密钥或没选模型，再解释为什么 AI 不能发送、为什么模型列表为空。',
  },
  {
    title: '排查聊天发送状态',
    steps: 'inspect_ai_chat_readiness -> inspect_ai_providers',
    description: '适合先确认当前聊天输入区到底缺什么前置条件，例如没选活动供应商、缺密钥、缺接口地址、没选模型，避免只凭界面现象猜测。',
  },
  {
    title: '追踪 AI 上游请求',
    steps: 'inspect_ai_upstream_logs -> inspect_ai_providers / inspect_ai_message_flow',
    description: '适合用户想看发给上游模型的真实入参、requestId、状态码、耗时或请求体预览时，先读脱敏后的 gonavi.log 请求记录，再结合供应商配置和当前消息流继续排查。',
  },
  {
    title: '排查 MCP 接入状态',
    steps: 'inspect_mcp_setup -> inspect_mcp_runtime_failures -> inspect_ai_runtime',
    description: '适合先确认当前配置了哪些 MCP 服务、哪些已启用、外部客户端有没有写入当前 GoNavi 路径，再结合 MCP 运行期失败日志判断为什么某个工具没暴露出来。',
  },
  {
    title: '远程 Agent 接入 GoNavi MCP',
    steps: 'inspect_mcp_remote_access -> inspect_mcp_setup -> inspect_ai_safety',
    description: '适合 OpenClaw/Hermans 部署在云端 Linux，但数据库连接和密码只在 Windows GoNavi 本机时，先生成 HTTP MCP、Bearer Token、隧道和安全边界指引。',
  },
  {
    title: '新增 MCP 填写指引',
    steps: 'inspect_mcp_authoring_guide -> inspect_mcp_draft -> inspect_mcp_setup',
    description: '适合先读真实字段说明、模板样例和整行命令拆分规则，再把用户贴出的命令或草稿交给真实校验器试算，最后结合当前 MCP 配置现状判断应该新增哪种启动方式。',
  },
  {
    title: '排查 Docker MCP 启动',
    steps: 'inspect_mcp_runtime_failures -> inspect_mcp_docker_setup -> inspect_mcp_draft',
    description: '适合用户按 Docker README 新增 MCP 后发现 0 个工具、容器一启动就退出，或不确定 docker run 参数是否拆对时，先看运行期失败原因，再检查 run、-i、镜像名和超时设置。',
  },
  {
    title: '查看 MCP 工具参数',
    steps: 'inspect_mcp_setup -> inspect_mcp_tool_schema',
    description: '适合先找到当前真实发现到的 MCP 工具 alias，再读取对应 inputSchema、必填字段、枚举和嵌套参数路径，避免调用外部 MCP 工具时乱填 arguments。',
  },
  {
    title: '查看当前提示与 Skills',
    steps: 'inspect_ai_guidance -> inspect_ai_runtime',
    description: '适合先确认当前自定义提示词、启用的 Skills、依赖工具和生效范围，再解释为什么 AI 当前会这样回答或为什么某个规则没有触发。',
  },
  {
    title: '查看当前 AI 上下文',
    steps: 'inspect_ai_context -> inspect_table_bundle / get_columns',
    description: '适合先确认这轮对话当前到底挂了哪些表结构，再继续做字段核对、表设计评审或 SQL 生成。',
  },
  {
    title: '查看当前连接',
    steps: 'inspect_current_connection -> get_databases / get_tables',
    description: '适合先确认当前活动数据源的类型、地址、当前库和 SSH/代理状态，再继续做库表探索或连接问题排查。',
  },
  {
    title: '核对数据源能力边界',
    steps: 'inspect_connection_capabilities -> inspect_current_connection',
    description: '适合先确认当前连接到底支不支持建库、删库、结果编辑、SQL 导出或近似计数，再解释为什么某些按钮没出现或某类操作只能只读。',
  },
  {
    title: '盘点本地连接资产',
    steps: 'inspect_saved_connections -> inspect_current_connection / get_databases',
    description: '适合先按关键词或类型筛出本地保存的数据源，再挑目标连接继续看当前状态或库表结构。',
  },
  {
    title: '诊断 Redis 拓扑',
    steps: 'inspect_redis_topology -> inspect_current_connection / inspect_app_logs',
    description: '适合用户问 Redis 哨兵、Cluster、多节点、切库失败或 SSH 隧道不可用时，先拿到状态分级、脱敏 URI、后端适配器、DB 语义和下一步动作。',
  },
  {
    title: '盘点外部 SQL 目录',
    steps: 'inspect_external_sql_directories -> inspect_workspace_tabs / inspect_active_tab',
    description: '适合先确认本地配置了哪些外部 SQL 目录、目录绑定到哪个连接/库，以及当前打开的 SQL 文件来自哪里，再继续分析脚本内容。',
  },
  {
    title: '读取外部 SQL 文件',
    steps: 'inspect_external_sql_directories -> inspect_external_sql_file -> inspect_active_tab',
    description: '适合先定位具体脚本路径，再直接读取目录中的 SQL 文件内容；如果这个文件已经在编辑器里打开，再继续结合当前页签草稿一起分析。',
  },
  {
    title: '读取当前页签',
    steps: 'inspect_active_tab -> get_columns / get_indexes / execute_sql',
    description: '适合先读取当前编辑器里的 SQL 草稿或当前表页签，再继续做字段核对、索引分析和只读验证。',
  },
  {
    title: '盘点当前工作区',
    steps: 'inspect_workspace_tabs -> inspect_active_tab -> get_columns / execute_sql',
    description: '适合先看当前打开了哪些 SQL / 表 / 命令页签，再切到目标页签继续做字段核对、对比分析和只读验证。',
  },
  {
    title: '查看当前快捷键配置',
    steps: 'inspect_shortcuts -> inspect_active_tab / inspect_workspace_tabs',
    description: '适合先确认当前 Win / Mac 快捷键、是否改过默认值，以及结果区、AI 面板、查询执行等动作到底该怎么按，再结合当前页签解释具体使用场景。',
  },
  {
    title: '回看最近执行记录',
    steps: 'inspect_recent_sql_logs -> get_columns / get_indexes / execute_sql',
    description: '适合追查刚刚执行失败的 SQL、慢查询耗时，或基于真实执行历史继续让 AI 给解释和优化建议。',
  },
  {
    title: '总结最近 SQL 活动',
    steps: 'inspect_recent_sql_activity -> inspect_recent_sql_logs -> inspect_current_connection',
    description: '适合先看最近到底以读还是写为主、有没有 DDL 或删除、哪个库最近报错最多，再决定继续下钻哪条日志或哪个连接。',
  },
  {
    title: '核对 SQL 编辑器事务',
    steps: 'inspect_sql_editor_transaction -> inspect_recent_sql_activity -> inspect_sql_risk',
    description: '适合先确认 SQL 编辑器 DML 是否会进入托管事务、当前是手动还是自动提交、有没有待提交事务，再解释 update/insert/delete 执行后的提交语义。',
  },
  {
    title: 'SQL 风险预检',
    steps: 'inspect_sql_risk -> inspect_ai_safety -> execute_sql',
    description: '适合用户要求执行、删除、更新、DDL 或批量 SQL 前，先检查语句数量、写入/DDL 风险、WHERE 条件和当前安全策略，再决定是否需要用户确认。',
  },
  {
    title: '排查应用日志',
    steps: 'inspect_app_logs -> inspect_mcp_setup / inspect_saved_connections / inspect_current_connection',
    description: '适合先回看 gonavi.log 尾部的 ERROR/WARN，再结合 MCP、连接和当前数据源状态继续定位启动异常、连接失败或外部工具拉起问题。',
  },
  {
    title: '排查连接失败与冷却',
    steps: 'inspect_recent_connection_failures -> inspect_current_connection / inspect_saved_connections / inspect_app_logs',
    description: '适合用户直接问“为什么连接不上”或已经看到冷却/验证失败提示时，先拿到结构化根因、最新地址和下一步建议，再决定回到连接配置还是看更长日志。',
  },
  {
    title: '排查 AI 气泡渲染异常',
    steps: 'inspect_ai_last_render_error -> inspect_active_tab / inspect_ai_runtime',
    description: '适合用户反馈 AI 某条消息空白、气泡局部报错但整个面板没挂时，先拿到最近一次被隔离的渲染异常快照，再回到具体会话和运行时上下文继续缩小范围。',
  },
  {
    title: '诊断 AI 消息流',
    steps: 'inspect_ai_message_flow -> inspect_ai_last_render_error / inspect_app_logs',
    description: '适合用户反馈回复被拆成多个气泡、工具调用后没继续回答、消息流状态不对时，先读取当前会话的真实消息结构和异常信号。',
  },
  {
    title: '诊断 AI 上下文体量',
    steps: 'inspect_ai_context_budget -> inspect_ai_context / inspect_ai_message_flow / inspect_ai_tool_catalog',
    description: '适合用户反馈 AI 变慢、乱答、上下文太大、工具结果过长或表结构挂太多时，先看消息、DDL、MCP schema、提示词和 Skills 的体量来源，再决定收窄上下文或拆任务。',
  },
  {
    title: '治理前端大文件',
    steps: 'inspect_codebase_hotspots -> inspect_ai_tool_catalog',
    description: '适合用户要求继续拆分几千行组件、评估下一步重构切入点，或 AI 修改 UI/AI/MCP 前先判断大文件拆分热点、风险和验证范围。',
  },
  {
    title: '复用历史 SQL',
    steps: 'inspect_saved_queries -> get_columns / execute_sql',
    description: '适合先找本地保存过的查询脚本，再核对字段和只读验证，避免把之前写过的 SQL 重新手打一遍。',
  },
  {
    title: '回看 AI 历史对话',
    steps: 'inspect_ai_sessions -> inspect_active_tab / inspect_saved_queries',
    description: '适合先定位之前聊过的 AI 会话、首条问题和最近回复，再继续复用当前页签或历史 SQL 上下文。',
  },
  {
    title: '查找模板片段',
    steps: 'inspect_sql_snippets',
    description: '适合先找团队已有的 SQL 片段模板、补全前缀和常用骨架，再决定是否继续改写。',
  },
  {
    title: '理解样例数据',
    steps: 'get_columns -> preview_table_rows',
    description: '适合先确认字段，再直接查看前几行真实样例数据和空值形态。',
  },
  {
    title: '只读验证',
    steps: 'get_columns -> preview_table_rows -> execute_sql',
    description: '适合生成 SQL 后做小范围结果核对，仍会受 AI 安全级别控制。',
  },
];

const stringifyHintValue = (value: unknown): string => {
  if (value === undefined) return '';
  if (value === null) return 'null';
  if (typeof value === 'string') return value;
  if (typeof value === 'number' || typeof value === 'boolean') return String(value);
  try {
    return JSON.stringify(value);
  } catch {
    return String(value);
  }
};

const readTypeLabel = (schema: Record<string, any>): string => {
  if (Array.isArray(schema.type)) {
    return schema.type.map((item) => String(item)).filter(Boolean).join(' | ') || 'any';
  }
  if (typeof schema.type === 'string' && schema.type.trim()) {
    return schema.type.trim();
  }
  if (Array.isArray(schema.enum) && schema.enum.length > 0) {
    return 'enum';
  }
  return 'any';
};

const readDefaultValue = (schema: Record<string, any>, description: string): string => {
  if (Object.prototype.hasOwnProperty.call(schema, 'default')) {
    return stringifyHintValue(schema.default);
  }
  const match = description.match(/默认\s*([^\s，,；;。)）]+)/u);
  return match?.[1]?.trim() || '';
};

const readExampleValue = (description: string): string => {
  const match = description.match(/(?:例如|示例值?[:：])\s*([^。；;\n]+)/u);
  return match?.[1]?.trim() || '';
};

export const describeBuiltinToolParameters = (tool: AIBuiltinToolInfo): AIBuiltinToolParameterHint[] => {
  const schema = tool.tool.function.parameters;
  const properties = schema && typeof schema === 'object' && typeof schema.properties === 'object'
    ? schema.properties
    : {};
  const required = new Set(
    Array.isArray(schema?.required) ? schema.required.map((item) => String(item)) : [],
  );

  return Object.entries(properties).map(([name, config]) => {
    const normalized = config && typeof config === 'object' ? config as Record<string, any> : {};
    const description = typeof normalized.description === 'string' ? normalized.description : '';
    return {
      name,
      required: required.has(name),
      typeLabel: readTypeLabel(normalized),
      description,
      enumValues: Array.isArray(normalized.enum) ? normalized.enum.map((item) => String(item)) : [],
      defaultValue: readDefaultValue(normalized, description),
      exampleValue: readExampleValue(description),
    };
  });
};

export const normalizeBuiltinToolCatalogSearch = (value: string): string =>
  value.trim().toLowerCase();

const matchesCatalogSearch = (keyword: string, values: unknown[]): boolean =>
  !keyword || values.some((value) => String(value || '').toLowerCase().includes(keyword));

export const filterBuiltinToolFlows = (
  flows: AIBuiltinToolFlow[],
  searchText: string,
): AIBuiltinToolFlow[] => {
  const keyword = normalizeBuiltinToolCatalogSearch(searchText);
  return flows.filter((flow) => matchesCatalogSearch(keyword, [
    flow.title,
    flow.steps,
    flow.description,
  ]));
};

export const filterBuiltinTools = (
  tools: AIBuiltinToolInfo[],
  searchText: string,
): AIBuiltinToolInfo[] => {
  const keyword = normalizeBuiltinToolCatalogSearch(searchText);
  return tools.filter((tool) => {
    const parameterDetails = describeBuiltinToolParameters(tool);
    return matchesCatalogSearch(keyword, [
      tool.name,
      tool.desc,
      tool.detail,
      tool.params,
      ...parameterDetails.flatMap((item) => [
        item.name,
        item.typeLabel,
        item.description,
        item.defaultValue,
        item.exampleValue,
        item.enumValues.join(' '),
      ]),
    ]);
  });
};
