// Shared source of truth for canonical (long-prefix) maxy MCP tool names.
//
// Claude Code's installed-plugin channel serves every plugin MCP tool under
// the long prefix `mcp__plugin_<plugin>_<server>__<tool>`. For every platform
// plugin the marketplace name, the MCP server key, and the directory basename
// are identical, so the canonical name is deterministically
// `mcp__plugin_<dir>_<dir>__<tool>`. This module is the single place that
// derives those names from each `platform/plugins/<dir>/PLUGIN.md`; the
// generator writes the committed artifact from it, the build gate diffs
// against it, and the session-manager cross-checks its tool surface against it.
//
// Scope: platform plugins only. Third-party bridge servers (playwright, etc.)
// also render under `mcp__plugin_*` but their tool names are upstream-owned and
// are NOT part of the maxy canonical set — the drift check treats a
// `mcp__plugin_*` name whose plugin segment is not a maxy plugin as a bridge
// pass, never validating it against this set.

import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const __dirname = dirname(fileURLToPath(import.meta.url))
export const MAXY_CODE_ROOT = resolve(__dirname, '..', '..', '..')
const PLATFORM_PLUGINS_ROOT = join(MAXY_CODE_ROOT, 'platform', 'plugins')

/** Long-prefix canonical name for a platform plugin tool. plugin === server
 *  === directory basename for every platform MCP plugin. */
export function canonicalToolName(plugin, tool) {
  return `mcp__plugin_${plugin}_${plugin}__${tool}`
}

function extractFrontmatter(md) {
  if (!md.startsWith('---')) return null
  const end = md.indexOf('\n---', 3)
  if (end < 0) return null
  return md.slice(3, end)
}

// Collect `- name: <x>` entries under a bare `tools:` block and `- <x>` entries
// under a bare `hidden:` block. Both contribute names a specialist may list in
// its `tools:` frontmatter, so both belong to the live set.
function parseToolNames(frontmatter) {
  const lines = frontmatter.split('\n')
  const names = []
  let mode = null // 'tools' | 'hidden' | null
  for (const line of lines) {
    if (/^tools\s*:/.test(line)) {
      mode = /^tools\s*:\s*$/.test(line) ? 'tools' : null
      continue
    }
    if (/^hidden\s*:/.test(line)) {
      mode = /^hidden\s*:\s*$/.test(line) ? 'hidden' : null
      continue
    }
    if (/^\S/.test(line) && line.trim() !== '') { mode = null; continue }
    if (mode === 'tools') {
      const m = line.match(/^\s+-\s+name:\s*(.+?)\s*$/)
      if (m) names.push(m[1])
    } else if (mode === 'hidden') {
      const m = line.match(/^\s+-\s+(.+?)\s*$/)
      if (m) names.push(m[1])
    }
  }
  return names
}

/** Returns { plugins, names } — `plugins` is the sorted list of maxy plugin
 *  directory basenames that declare a tool surface; `names` is the sorted list
 *  of canonical long-prefix tool names across all of them. */
export function computeCanonicalToolNames(pluginsRoot = PLATFORM_PLUGINS_ROOT) {
  const plugins = []
  const names = new Set()
  if (!existsSync(pluginsRoot)) return { plugins, names: [] }
  for (const entry of readdirSync(pluginsRoot).sort()) {
    if (entry.startsWith('.')) continue
    const dir = join(pluginsRoot, entry)
    try { if (!statSync(dir).isDirectory()) continue } catch { continue }
    const manifest = join(dir, 'PLUGIN.md')
    if (!existsSync(manifest)) continue
    const fm = extractFrontmatter(readFileSync(manifest, 'utf-8'))
    if (fm === null) continue
    const toolNames = parseToolNames(fm)
    if (toolNames.length === 0) continue
    plugins.push(entry)
    for (const t of toolNames) names.add(canonicalToolName(entry, t))
  }
  return { plugins: plugins.sort(), names: Array.from(names).sort() }
}
