export const DEFAULT_CLAUDE_BUILT_IN_TOOLS = [
  "Read",
  "Write",
  "Bash",
  "Glob",
  "Grep",
  "WebFetch",
  "WebSearch",
] as const;

export const CPH_HUB_MCP_SERVER_NAME = "cph_hub";
export const CPH_HUB_MCP_TOOL_IDS = [
  "send_file",
  "feishu_read_context",
  "feishu_download_resource",
  "request_approval",
  "convert_pdf_to_md",
] as const;

export type CphHubMcpToolId = (typeof CPH_HUB_MCP_TOOL_IDS)[number];

export interface ClaudeSdkToolConfig {
  readonly tools: readonly string[];
  readonly allowedTools: readonly string[];
}

const ROLE_TOOL_TO_CLAUDE_BUILT_INS = new Map<string, readonly string[]>([
  ["read_file", ["Read"]],
  ["write_file", ["Write"]],
  ["list_files", ["Glob"]],
  ["search_files", ["Grep"]],
  ["bash", ["Bash"]],
  // ADR-0017 replaced cph custom tools with Bash commands. Granting either
  // cph role tool therefore exposes the SDK Bash tool; cph-only Bash narrowing
  // would need a separate command-policy layer.
  ["cph_check", ["Bash"]],
  ["cph_build", ["Bash"]],
  ["web_fetch", ["WebFetch"]],
  ["web_search", ["WebSearch"]],
  ["Read", ["Read"]],
  ["Write", ["Write"]],
  ["Bash", ["Bash"]],
  ["Glob", ["Glob"]],
  ["Grep", ["Grep"]],
  ["WebFetch", ["WebFetch"]],
  ["WebSearch", ["WebSearch"]],
]);

const ROLE_TOOL_TO_CPH_HUB_MCP_TOOL = new Map<string, CphHubMcpToolId>([
  ["send_file", "send_file"],
  ["feishu_read_context", "feishu_read_context"],
  ["feishu_download_resource", "feishu_download_resource"],
  ["request_approval", "request_approval"],
  ["convert_pdf_to_md", "convert_pdf_to_md"],
  ["mcp__cph_hub__send_file", "send_file"],
  ["mcp__cph_hub__feishu_read_context", "feishu_read_context"],
  ["mcp__cph_hub__feishu_download_resource", "feishu_download_resource"],
  ["mcp__cph_hub__request_approval", "request_approval"],
  ["mcp__cph_hub__convert_pdf_to_md", "convert_pdf_to_md"],
]);

const SUPPORTED_ROLE_TOOLS = new Set([
  ...ROLE_TOOL_TO_CLAUDE_BUILT_INS.keys(),
  ...ROLE_TOOL_TO_CPH_HUB_MCP_TOOL.keys(),
]);

export function claudeSdkToolConfigForRole(roleTools: readonly string[] | undefined): ClaudeSdkToolConfig {
  if (roleTools === undefined) {
    const mcpTools = CPH_HUB_MCP_TOOL_IDS.map(claudeMcpToolName);
    return {
      tools: [...DEFAULT_CLAUDE_BUILT_IN_TOOLS],
      allowedTools: [...DEFAULT_CLAUDE_BUILT_IN_TOOLS, ...mcpTools],
    };
  }

  const builtIns: string[] = [];
  const allowedTools: string[] = [];
  for (const roleTool of roleTools) {
    assertSupportedRoleTool(roleTool);
    for (const tool of ROLE_TOOL_TO_CLAUDE_BUILT_INS.get(roleTool) ?? []) {
      pushUnique(builtIns, tool);
      pushUnique(allowedTools, tool);
    }

    const mcpTool = ROLE_TOOL_TO_CPH_HUB_MCP_TOOL.get(roleTool);
    if (mcpTool !== undefined) {
      pushUnique(allowedTools, claudeMcpToolName(mcpTool));
    }
  }

  return { tools: builtIns, allowedTools };
}

export function cphHubMcpToolsForRole(roleTools: readonly string[] | undefined): readonly CphHubMcpToolId[] {
  if (roleTools === undefined) return [...CPH_HUB_MCP_TOOL_IDS];

  const tools: CphHubMcpToolId[] = [];
  for (const roleTool of roleTools) {
    assertSupportedRoleTool(roleTool);
    const mcpTool = ROLE_TOOL_TO_CPH_HUB_MCP_TOOL.get(roleTool);
    if (mcpTool !== undefined) pushUnique(tools, mcpTool);
  }
  return tools;
}

export function roleToolsAllow(roleTools: readonly string[] | undefined, roleTool: string): boolean {
  if (roleTools === undefined) return true;
  for (const configured of roleTools) {
    assertSupportedRoleTool(configured);
    if (configured === roleTool) return true;
    if (ROLE_TOOL_TO_CPH_HUB_MCP_TOOL.get(configured) === roleTool) return true;
  }
  return false;
}

export function assertSupportedRoleTools(roleTools: readonly string[]): void {
  for (const roleTool of roleTools) assertSupportedRoleTool(roleTool);
}

function claudeMcpToolName(tool: CphHubMcpToolId): string {
  return `mcp__${CPH_HUB_MCP_SERVER_NAME}__${tool}`;
}

function assertSupportedRoleTool(roleTool: string): void {
  if (!SUPPORTED_ROLE_TOOLS.has(roleTool)) {
    throw new Error(`unknown role tool id: ${roleTool}`);
  }
}

function pushUnique<T>(items: T[], item: T): void {
  if (!items.includes(item)) items.push(item);
}
