/**
 * Phase 3b post-review — tool_name label normalization.
 */
import { describe, it, expect } from 'vitest';
import { Registry } from 'prom-client';
import { normalizeToolNameForMetric, BUILTIN_TOOL_NAMES } from './tool-name-allowlist.js';
import { createWorkerMetrics } from './worker-metrics.js';
import { TOOL_DEFS as SLIDE_DEFS } from '../engine/tools/slide.js';
import { TOOL_DEFS as MSLEARN_DEFS } from '../engine/tools/ms-learn.js';
import { TOOL_DEFS as OFFICE_DEFS } from '../engine/tools/office.js';

describe('normalizeToolNameForMetric', () => {
  it('passes built-in tool names through verbatim', () => {
    expect(normalizeToolNameForMetric('Read')).toBe('Read');
    expect(normalizeToolNameForMetric('WebFetch')).toBe('WebFetch');
    expect(normalizeToolNameForMetric('SpawnSubTask')).toBe('SpawnSubTask');
  });

  it('collapses every mcp__* name to a single mcp bucket', () => {
    expect(normalizeToolNameForMetric('mcp__alpha__foo')).toBe('mcp');
    expect(normalizeToolNameForMetric('mcp__beta__bar')).toBe('mcp');
    expect(normalizeToolNameForMetric('mcp__github__create_issue')).toBe('mcp');
  });

  it('collapses anything else to unknown', () => {
    expect(normalizeToolNameForMetric('some_random_tool')).toBe('unknown');
    expect(normalizeToolNameForMetric('')).toBe('unknown');
    expect(normalizeToolNameForMetric('not_a_real_tool_name')).toBe('unknown');
  });

  it('does not treat partial mcp_ prefix as MCP (must be `mcp__`)', () => {
    expect(normalizeToolNameForMetric('mcp_foo')).toBe('unknown');
    expect(normalizeToolNameForMetric('mcpwhatever')).toBe('unknown');
  });

  it('runtime tools (transition, complete) pass through', () => {
    expect(normalizeToolNameForMetric('transition')).toBe('transition');
    expect(normalizeToolNameForMetric('complete')).toBe('complete');
  });

  it('BUILTIN_TOOL_NAMES contains the documented set of built-ins', () => {
    // Smoke-checks: ensure we didn't accidentally drop a known tool.
    const required = ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'WebFetch', 'BrowseWeb'];
    for (const name of required) {
      expect(BUILTIN_TOOL_NAMES.has(name)).toBe(true);
    }
  });

  it('label cardinality stays bounded: many mcp__* names share one bucket', async () => {
    const reg = new Registry();
    const m = createWorkerMetrics(reg, 'aao_worker_n');
    // Simulate 100 distinct mcp__* names.
    for (let i = 0; i < 100; i += 1) {
      m.toolCallsTotal
        .labels({ tool_name: normalizeToolNameForMetric(`mcp__server${i}__tool${i}`), success: 'true' })
        .inc();
    }
    const dump = await reg.metrics();
    // All 100 calls should have collapsed into the single mcp bucket.
    expect(dump).toMatch(/aao_worker_n_tool_calls_total\{tool_name="mcp",success="true"\} 100/);
    // No mcp__ literals should leak into the metric body.
    expect(dump).not.toMatch(/tool_name="mcp__/);
  });
});

// Audit 2026-06-08 (P1, metrics): the allowlist carried GHOST names
// (CreateSlide, MsLearn{Fetch,Read,Search,Summarize}) that no tool emits, while
// the REAL slide (SetTheme/AddSlide/BuildPptx/ResetSlides) and ms-learn
// (Search/Fetch/SearchCache/RefreshMicrosoftLearn[Cache]) tools were missing —
// so every real call collapsed to 'unknown' in metrics. Pin the allowlist to
// the actual TOOL_DEFS so it can't drift again.
describe('metrics allowlist ↔ real tool definitions (audit regression)', () => {
  const realNames = [
    ...Object.keys(SLIDE_DEFS),
    ...Object.keys(MSLEARN_DEFS),
    ...Object.keys(OFFICE_DEFS),
  ];

  it('every real slide/ms-learn/office tool normalizes to itself (not "unknown")', () => {
    for (const name of realNames) {
      expect(normalizeToolNameForMetric(name)).toBe(name);
    }
  });

  it('every real slide/ms-learn/office tool is present in BUILTIN_TOOL_NAMES', () => {
    for (const name of realNames) {
      expect(BUILTIN_TOOL_NAMES.has(name)).toBe(true);
    }
  });

  it('carries no ghost names that no real tool emits', () => {
    for (const ghost of ['CreateSlide', 'MsLearnFetch', 'MsLearnRead', 'MsLearnSearch', 'MsLearnSummarize']) {
      expect(BUILTIN_TOOL_NAMES.has(ghost)).toBe(false);
    }
  });
});
