import {
  getToolCategoryMap,
  listToolCategories,
  SENSITIVE_CATEGORIES,
  SENSITIVE_TOOLS,
  META_TOOLS,
} from './tools/tool-categories.js';

export interface WorkspaceToolPolicy {
  disabledSafe?: string[];
  enabledSensitive?: string[];
}

export function parseToolPolicy(json: string | null): WorkspaceToolPolicy {
  if (!json) return {};
  try {
    const o = JSON.parse(json);
    if (o && typeof o === 'object') {
      return {
        disabledSafe: Array.isArray(o.disabledSafe)
          ? o.disabledSafe.filter((s: unknown) => typeof s === 'string')
          : undefined,
        enabledSensitive: Array.isArray(o.enabledSensitive)
          ? o.enabledSensitive.filter((s: unknown) => typeof s === 'string')
          : undefined,
      };
    }
  } catch { /* fall through */ }
  return {};
}

export async function resolveWorkspaceTools(
  policy: WorkspaceToolPolicy,
): Promise<{ allowedTools: string[]; editAllowed: boolean }> {
  const catMap = await getToolCategoryMap();      // name -> category
  const allCats = await listToolCategories();
  const disabledSafe = new Set(policy.disabledSafe ?? []);
  const enabledSensitive = new Set(policy.enabledSensitive ?? []);

  // safe categories = all - sensitive categories, minus any the policy disables
  const effectiveCats = new Set<string>();
  for (const c of allCats) {
    if (SENSITIVE_CATEGORIES.has(c)) {
      if (enabledSensitive.has(c)) effectiveCats.add(c);     // sensitive cat opted-in
    } else if (!disabledSafe.has(c)) {
      effectiveCats.add(c);                                   // safe cat (default on unless disabled)
    }
  }

  const tools = new Set<string>();
  for (const [name, cat] of catMap) {
    if (!effectiveCats.has(cat)) continue;
    if (SENSITIVE_TOOLS.has(name)) continue;                  // Bash excluded here; opt-in below
    tools.add(name);
  }
  // individual sensitive tools (Bash) only when opted in
  for (const t of SENSITIVE_TOOLS) {
    if (enabledSensitive.has(t)) tools.add(t);
  }
  for (const m of META_TOOLS) tools.add(m);                  // META always

  // MCP pass-through: MCP availability is governed by per-space server connection
  // (opt-in by connecting a server to the workspace), NOT by this builtin policy.
  // The MCP aggregator returns nothing unless the allowlist carries an `mcp__`
  // pattern, and it independently scopes results to the job's space + valid token.
  // So always carry the `mcp__*` wildcard; the connection/space/token gate decides
  // what actually surfaces. (Without this, the workspace-tool-policy migration
  // would drop the `mcp__*` patterns that movement.allowed_tools used to carry,
  // hiding every MCP tool — see fix/workspace-tool-policy-mcp.)
  tools.add('mcp__*');

  return { allowedTools: [...tools], editAllowed: tools.has('Write') || tools.has('Edit') };
}
