import type { AgentRunMode } from "./AgentSdkAdapter.ts";
import {
  isTaskHotPathBody,
  isPmDispatchForbiddenBody,
} from "../pm/pmAdminRejectPrompt.ts";
import {
  EXECUTOR_TOOLS,
  isLeaderRoleAgentId,
  LEADER_RUNTIME_HOT_PATH_TOOLS,
  RUNTIME_HOT_PATH_BLOCKED_SET,
} from "../skill/FcopToolProfile.ts";
import {
  extendAdminRejectColdPathWithWorkspaceRead,
  filterPmDevColdDispatchTools,
} from "../pm/pmDevDispatchPolicy.ts";

/** Profile mode exposes full FCOP_ALLOWED_TOOLS (leader ≈28). Trim mode uses heuristics below. */
export const GEMINI_DEFAULT_MAX_TOOLS = 32;
export const GEMINI_DEFAULT_TOOL_TOKEN_BUDGET = 14_000;
export const GEMINI_TOOL_SCHEMA_TOKEN_ESTIMATE = 430;

export type GeminiToolSelectionMode = "profile" | "trim" | "full";

/** Default profile = full role allowlist; set CODEFLOW_GEMINI_TOOL_MODE=trim to cap by prompt heuristics. */
export function resolveGeminiToolSelectionMode(
  envValue: string | undefined = process.env.CODEFLOW_GEMINI_TOOL_MODE,
): GeminiToolSelectionMode {
  const mode = (envValue ?? "profile").trim().toLowerCase();
  if (mode === "full" || mode === "profile" || mode === "trim") {
    return mode;
  }
  return "profile";
}

const ADMIN_REJECT_COLD_PATH_RE =
  /admin.*打回|cold path|最高优先级.*打回|admin 判定打回|admin_reject|admin reject cold path/i;

const ADMIN_REJECT_HOT_PATH_RE =
  /admin.*打回.*hot\s*path|admin\s*判定打回.*hot\s*path|admin\s*↔\s*pm.*打回.*hot\s*path|hot path · pm 亲自完成治理核查|不代表可修改产品代码|admin reject hot path/i;

const PM_SELF_REPORT_ONLY_RUN_MODE_RE =
  /run_mode:\s*\*{0,2}pm_self_report_only|pm_self_report_only/i;

/** pm_self_report_only：仅最终 write_report + 可选只读冻结锚点探针。 */
export const PM_SELF_REPORT_ONLY_TOOLS = [
  "write_report",
  "read_file",
  "grep_files",
] as const;

/** pm_self_report_only 运行时 defense-in-depth 拦截集合。 */
export const PM_SELF_REPORT_ONLY_BLOCKED = new Set([
  "write_task",
  "create_task",
  "archive_task",
  "finish_task",
  "approve_task",
  "reject_task",
  "submit_task",
  "list_tasks",
  "read_task",
  "inspect_task",
  "list_reports",
  "read_report",
  "fcop_report",
  "fcop_check",
  "fcop_audit",
  "write_review",
  "list_issues",
  "write_issue",
  "get_team_status",
  "drop_suggestion",
  "mark_human_approved",
]);

function filterPmSelfReportOnlyTools(
  normalizedAllowed: readonly string[],
): string[] {
  const allowed = new Set(normalizedAllowed);
  return PM_SELF_REPORT_ONLY_TOOLS.filter((n) => allowed.has(n));
}

/** Google PM 最小闭环：严格 self-report-only，禁止派发与 lifecycle 治理工具。 */
export function isPmSelfReportOnlyMode(
  prompt: string,
  agentId?: string,
  runMode?: AgentRunMode,
): boolean {
  if (runMode === "pm_self_report_only") return true;
  if (!prompt.trim()) return false;
  const id = agentId ?? "";
  if (id && !isLeaderRoleAgentId(id)) return false;
  return PM_SELF_REPORT_ONLY_RUN_MODE_RE.test(`${id}\n${prompt}`);
}

/** ADMIN 打回 Hot Path：PM 治理核查/协调；需要实现时可 write_task，禁止 write_file 写产品。 */
const ADMIN_REJECT_HOT_PATH_TOOLS = [
  "write_report",
  "write_task",
  "create_task",
  "fcop_report",
  "fcop_check",
  "fcop_audit",
  "read_file",
  "grep_files",
  "list_dir",
  "submit_task",
  "list_tasks",
  "list_reports",
  "read_report",
  "list_issues",
  "write_issue",
  "drop_suggestion",
  "get_team_status",
] as const;

/** PM 自包含 Hot Path（最小闭环冒烟等）：正文禁止派发，不含 write_task。 */
const PM_SELF_EXECUTE_HOT_PATH_TOOLS = ADMIN_REJECT_HOT_PATH_TOOLS.filter(
  (n) => n !== "write_task" && n !== "create_task",
);

/** PM/leader 面板 chat 或 wake 进入 ADMIN 打回 Hot Path 时的特征。 */
export function isAdminRejectHotPathPrompt(
  prompt: string,
  agentId?: string,
): boolean {
  if (!prompt.trim()) return false;
  const id = agentId ?? "";
  if (id && !isLeaderRoleAgentId(id)) return false;
  return ADMIN_REJECT_HOT_PATH_RE.test(`${id}\n${prompt}`);
}

/** PM 自包含执行（最小闭环冒烟等）：Hot Path 亲自执行，禁止派发；非 ADMIN 打回 Cold Path。 */
export function isPmSelfExecuteHotPathPrompt(
  prompt: string,
  agentId?: string,
): boolean {
  if (!prompt.trim()) return false;
  const id = agentId ?? "";
  if (id && !isLeaderRoleAgentId(id)) return false;
  if (isAdminRejectHotPathPrompt(prompt, agentId)) return false;
  if (isTaskHotPathBody(prompt)) return true;
  return false;
}

function filterAdminRejectHotPathTools(normalizedAllowed: readonly string[]): string[] {
  const allowed = new Set(normalizedAllowed);
  return ADMIN_REJECT_HOT_PATH_TOOLS.filter((n) => allowed.has(n));
}

function filterPmSelfExecuteHotPathTools(normalizedAllowed: readonly string[]): string[] {
  const allowed = new Set(normalizedAllowed);
  return PM_SELF_EXECUTE_HOT_PATH_TOOLS.filter((n) => allowed.has(n));
}

function selectPmHotPathTools(
  prompt: string,
  agentId: string,
  normalizedAllowed: readonly string[],
): string[] {
  if (isAdminRejectHotPathPrompt(prompt, agentId)) {
    return filterAdminRejectHotPathTools(normalizedAllowed);
  }
  return filterPmSelfExecuteHotPathTools(normalizedAllowed);
}

/** ADMIN 打回 Cold Path：优先派单，禁止 write_report ack。 */
const ADMIN_REJECT_COLD_DISPATCH_TOOLS = [
  "write_task",
  "create_task",
  "list_tasks",
  "list_reports",
  "read_report",
  "list_issues",
  "fcop_report",
  "get_team_status",
  "write_issue",
  "drop_suggestion",
] as const;

function filterAdminRejectColdPathTools(normalizedAllowed: readonly string[]): string[] {
  const allowed = new Set(normalizedAllowed);
  return ADMIN_REJECT_COLD_DISPATCH_TOOLS.filter((n) => allowed.has(n));
}

function selectAdminRejectColdPathTools(
  normalizedAllowed: readonly string[],
): string[] {
  return extendAdminRejectColdPathWithWorkspaceRead(
    filterAdminRejectColdPathTools(normalizedAllowed),
    normalizedAllowed,
  );
}

/** PM dev cold dispatch：只读 workspace + patch 写入 DEV 子任务，禁止 write_file。 */
export function isPmDevColdDispatchContext(
  prompt: string,
  agentId?: string,
  runMode?: AgentRunMode,
): boolean {
  if (isPmSelfReportOnlyMode(prompt, agentId, runMode)) return false;
  const id = agentId ?? "";
  if (id && !isLeaderRoleAgentId(id)) return false;
  if (isAdminRejectHotPathPrompt(prompt, agentId)) return false;
  if (isPmSelfExecuteHotPathPrompt(prompt, agentId)) return false;
  if (isRuntimeTaskDispatchPrompt(prompt)) return true;
  if (isAdminRejectColdPathPrompt(prompt, agentId)) return true;
  return false;
}

/** PM/leader 面板 chat 或 wake 进入 ADMIN 打回 Cold Path 时的特征（须查完整 prompt，勿仅用 split 后 userText）。 */
export function isAdminRejectColdPathPrompt(
  prompt: string,
  agentId?: string,
): boolean {
  if (!prompt.trim()) return false;
  if (isAdminRejectHotPathPrompt(prompt, agentId)) return false;
  if (isPmSelfExecuteHotPathPrompt(prompt, agentId)) return false;
  const id = agentId ?? "";
  if (id && !isLeaderRoleAgentId(id)) return false;
  return ADMIN_REJECT_COLD_PATH_RE.test(`${id}\n${prompt}`);
}

/**
 * TaskDispatcher 在 header 末尾用 `\n\n---` 分隔 system/user。
 * Admin reject 预载 TASK（markdown 代码块）正文内也可能含 `\n\n---`（如 state_history），禁止误 split。
 */
export function shouldSplitPromptOnSystemDelimiter(
  prompt: string,
  agentId?: string,
): boolean {
  if (!prompt.includes("\n\n---")) return false;
  if (isAdminRejectColdPathPrompt(prompt, agentId)) return false;
  if (isAdminRejectHotPathPrompt(prompt, agentId)) return false;
  return isRuntimeTaskDispatchPrompt(prompt);
}

/** Runtime 已把 TASK 正文注入 prompt 时的特征（task-report 热路径）。 */
export function isRuntimeTaskDispatchPrompt(prompt: string): boolean {
  return (
    /任务正文已在|TASK 正文已在|Runtime 已预载|already loaded|no [`']claim_task|no [`']read_task/i.test(
      prompt,
    ) ||
    /Step 1.*write_report|payload.*TASK-\d{8}-\d{3,}/i.test(prompt)
  );
}

function parsePositiveInt(value: string | undefined, fallback: number): number {
  const parsed = Number.parseInt(value || "", 10);
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}

/**
 * 在 FCOP_ALLOWED_TOOLS 白名单内按 prompt/agent 裁剪 Gemini 工具声明。
 * Runtime 热路径下 executor 仅保留回执三件套；leader（PM 等）额外保留派单工具。
 */
export function selectGeminiToolNames(
  allowedTools: readonly string[],
  prompt: string,
  agentId: string,
  options?: { runMode?: AgentRunMode },
): string[] {
  const normalizedAllowed = [...new Set(allowedTools.filter(Boolean))];
  if (normalizedAllowed.length === 0) return [];

  if (isPmSelfReportOnlyMode(prompt, agentId, options?.runMode)) {
    return filterPmSelfReportOnlyTools(normalizedAllowed);
  }

  if (isRuntimeTaskDispatchPrompt(prompt)) {
    if (
      isAdminRejectHotPathPrompt(prompt, agentId) ||
      isPmSelfExecuteHotPathPrompt(prompt, agentId)
    ) {
      return selectPmHotPathTools(prompt, agentId, normalizedAllowed);
    }
    const adminRejectColdPath = isAdminRejectColdPathPrompt(prompt, agentId);
    if (adminRejectColdPath) {
      return selectAdminRejectColdPathTools(normalizedAllowed);
    }
    if (isLeaderRoleAgentId(agentId)) {
      return filterPmDevColdDispatchTools(normalizedAllowed);
    }
    const hot: string[] = [...EXECUTOR_TOOLS];
    const allowed = new Set(normalizedAllowed);
    return hot.filter(
      (n) => allowed.has(n) && !RUNTIME_HOT_PATH_BLOCKED_SET.has(n),
    );
  }

  if (
    isAdminRejectHotPathPrompt(prompt, agentId) ||
    isPmSelfExecuteHotPathPrompt(prompt, agentId)
  ) {
    return selectPmHotPathTools(prompt, agentId, normalizedAllowed);
  }
  if (isAdminRejectColdPathPrompt(prompt, agentId)) {
    return selectAdminRejectColdPathTools(normalizedAllowed);
  }

  const mode = resolveGeminiToolSelectionMode();
  const adminRejectHotPathEarly = isAdminRejectHotPathPrompt(prompt, agentId);
  const adminRejectColdPathEarly = isAdminRejectColdPathPrompt(prompt, agentId);
  if (mode === "full" || mode === "profile") {
    if (adminRejectHotPathEarly) {
      return selectPmHotPathTools(prompt, agentId, normalizedAllowed);
    }
    if (adminRejectColdPathEarly) {
      return selectAdminRejectColdPathTools(normalizedAllowed);
    }
    return normalizedAllowed;
  }

  const allowed = new Set(normalizedAllowed);
  const lower = `${agentId}\n${prompt}`.toLowerCase();
  const adminRejectHotPath = adminRejectHotPathEarly;
  const adminRejectColdPath = adminRejectColdPathEarly;

  const maxTools = parsePositiveInt(
    process.env.CODEFLOW_GEMINI_MAX_TOOLS,
    GEMINI_DEFAULT_MAX_TOOLS,
  );
  const tokenBudget = parsePositiveInt(
    process.env.CODEFLOW_GEMINI_TOOL_TOKEN_BUDGET,
    GEMINI_DEFAULT_TOOL_TOKEN_BUDGET,
  );
  const budgetMaxTools = Math.max(
    1,
    Math.floor(tokenBudget / GEMINI_TOOL_SCHEMA_TOKEN_ESTIMATE),
  );
  const effectiveMaxTools = Math.min(maxTools, budgetMaxTools);

  if (normalizedAllowed.length <= effectiveMaxTools) {
    if (adminRejectHotPath) {
      return selectPmHotPathTools(prompt, agentId, normalizedAllowed);
    }
    if (adminRejectColdPath) {
      return selectAdminRejectColdPathTools(normalizedAllowed);
    }
    return normalizedAllowed;
  }

  const selected: string[] = [];
  const add = (...names: string[]) => {
    for (const name of names) {
      if (selected.length >= effectiveMaxTools) return;
      if (adminRejectColdPath && name === "write_report") continue;
      if (allowed.has(name) && !selected.includes(name)) {
        selected.push(name);
      }
    }
  };

  if (adminRejectHotPath) {
    add(
      "write_report",
      "write_task",
      "create_task",
      "fcop_report",
      "fcop_check",
      "read_file",
      "grep_files",
      "submit_task",
      "list_tasks",
      "drop_suggestion",
    );
  } else if (adminRejectColdPath) {
    add(
      "write_task",
      "create_task",
      "list_tasks",
      "fcop_report",
      "get_team_status",
      "write_issue",
      "drop_suggestion",
      "read_file",
      "grep_files",
      "list_dir",
    );
  } else {
    add(
      "write_report",
      "write_issue",
      "drop_suggestion",
      "fcop_report",
      "get_team_status",
      "list_tasks",
    );
  }

  const pmSelfExecute = isPmSelfExecuteHotPathPrompt(prompt, agentId);
  const dispatchForbidden = isPmDispatchForbiddenBody(prompt);
  if (
    !pmSelfExecute &&
    !dispatchForbidden &&
    (isLeaderRoleAgentId(agentId) ||
      (/(pm|planner|派发|分派|dispatch|任务|task)/i.test(lower) &&
        !/不(?:调用|派).*write_task|do not dispatch|not rework dispatch/i.test(
          lower,
        )) ||
      (/write_task/i.test(lower) &&
        !/不(?:调用|派).*write_task|禁止.*write_task|do not write_task/i.test(
          lower,
        )))
  ) {
    add("write_task", "create_task", "submit_task");
    if (/(inspect|诊断|审查.*任务文件)/i.test(lower)) {
      add("inspect_task");
    }
  }
  if (/(review|评审|审核|审查|verdict|needs_human|人工|approve|reject)/i.test(lower)) {
    add(
      "write_review",
      "list_reviews",
      "read_review",
      "mark_human_approved",
      "approve_task",
      "reject_task",
    );
  }
  if (/(report|报告|汇报)/i.test(lower)) {
    add("list_reports", "read_report");
  }
  if (/(issue|问题|阻塞|故障|bug|error|失败)/i.test(lower)) {
    add("list_issues", "write_issue");
  }
  if (/(archive|history|归档|历史)/i.test(lower)) {
    add("archive_task", "archive_to_history", "list_history", "read_history_task");
  }
  if (/(check|audit|巡检|审计|诊断|status|状态)/i.test(lower)) {
    add("fcop_check", "fcop_audit", "list_governance_events");
  }

  for (const name of normalizedAllowed) {
    if (selected.length >= effectiveMaxTools) break;
    if (adminRejectColdPath && name === "write_report") continue;
    if (RUNTIME_HOT_PATH_BLOCKED_SET.has(name)) continue;
    if (!selected.includes(name)) selected.push(name);
  }

  if (adminRejectColdPath) {
    return extendAdminRejectColdPathWithWorkspaceRead(selected, normalizedAllowed);
  }

  return selected;
}
