#!/usr/bin/env bun
/**
 * Generate a skill catalog with overlap matrix from the skills/ directory.
 *
 * Usage: bun run scripts/generate-catalog.ts
 *
 * Outputs: generated/skill-catalog.md
 */

import { stat, writeFile, mkdir } from "node:fs/promises";
import { join, resolve } from "node:path";
import { globToRegex } from "../hooks/patterns.mjs";
import type { SkillEntry } from "../hooks/patterns.mjs";
import { loadValidatedSkillMap } from "../src/shared/skill-map-loader.ts";

const ROOT = resolve(import.meta.dirname, "..");
const SKILLS_DIR = join(ROOT, "skills");
const OUTPUT_PATH = join(ROOT, "generated", "skill-catalog.md");

// Well-known files that many skills compete over
const OVERLAP_TARGETS = [
  "vercel.json",
  "apps/web/vercel.json",
  "middleware.ts",
  "middleware.js",
  "src/middleware.ts",
  "next.config.ts",
  "next.config.js",
  "next.config.mjs",
  ".env",
  ".env.local",
  ".env.production",
  ".mcp.json",
  "turbo.json",
  "app/api/chat/route.ts",
  "app/api/completion/route.ts",
  "app/layout.tsx",
  "src/app/layout.tsx",
  "pages/api/auth/[...nextauth].ts",
  "instrumentation.ts",
  "lib/ai/index.ts",
  "lib/cache/index.ts",
  "lib/workflow/index.ts",
  "components.json",
  "components/ui/button.tsx",
  "integration.json",
  "flags.ts",
  "lib/flags/index.ts",
  ".vercel/project.json",
  ".github/workflows/deploy.yml",
  "playwright.config.ts",
  "api/hello.ts",
  "pages/api/hello.ts",
  "app/api/bot/route.ts",
  "lib/bot/index.ts",
];

// Well-known bash commands that trigger skills
const BASH_OVERLAP_TARGETS = [
  "vercel deploy",
  "vercel dev",
  "vercel env pull",
  "vercel env add",
  "vercel logs",
  "vercel build",
  "next dev",
  "next build",
  "next dev --turbo",
  "npm run dev",
  "pnpm dev",
  "bun run dev",
  "npx v0 generate",
  "npx shadcn add button",
  "turbo run build",
  "npm install ai @ai-sdk/openai",
  "pnpm add @vercel/blob",
  "npm install @vercel/flags",
  "npx create-next-app",
  "vercel integration add",
  "vercel firewall",
];

interface CatalogSkillEntry extends SkillEntry {
  slug: string;
}

function matchesPath(skill: SkillEntry, filePath: string): boolean {
  for (const pat of skill.pathPatterns) {
    try {
      const regex = globToRegex(pat);
      if (regex.test(filePath)) return true;
    } catch {
      // skip broken patterns
    }
  }
  return false;
}

function matchesBash(skill: SkillEntry, command: string): boolean {
  for (const pat of skill.bashPatterns) {
    try {
      if (new RegExp(pat).test(command)) return true;
    } catch {
      // skip broken patterns
    }
  }
  return false;
}

async function main() {
  const { skills: skillMap, buildDiagnostics } = loadValidatedSkillMap(SKILLS_DIR);

  if (buildDiagnostics.length > 0) {
    console.warn(`Skill build warnings (${buildDiagnostics.length}):`);
    for (const d of buildDiagnostics) {
      console.warn(`  - ${d}`);
    }
  }
  const skills: CatalogSkillEntry[] = Object.entries(skillMap)
    .map(([slug, config]: [string, any]) => ({
      slug,
      priority: config.priority,
      pathPatterns: config.pathPatterns ?? [],
      bashPatterns: config.bashPatterns ?? [],
      importPatterns: config.importPatterns ?? [],
    }))
    .sort((a, b) => b.priority - a.priority || a.slug.localeCompare(b.slug));

  const lines: string[] = [];

  // Header
  lines.push("# Skill Catalog");
  lines.push("");
  lines.push(`> Auto-generated by \`scripts/generate-catalog.ts\` — do not edit manually.`);
  lines.push(`> Generated: ${new Date().toISOString()}`);
  lines.push(`> Skills: ${skills.length}`);
  lines.push("");

  // Table of contents
  lines.push("## Table of Contents");
  lines.push("");
  lines.push("- [Skill Index](#skill-index)");
  lines.push("- [Path Overlap Matrix](#path-overlap-matrix)");
  lines.push("- [Bash Overlap Matrix](#bash-overlap-matrix)");
  lines.push("- [Skills by Priority](#skills-by-priority)");
  lines.push("");

  // Skill index
  lines.push("## Skill Index");
  lines.push("");
  lines.push("| Skill | Priority | Path Patterns | Bash Patterns | Import Patterns |");
  lines.push("|-------|----------|---------------|---------------|-----------------|");

  for (const s of skills) {
    const pathCount = s.pathPatterns.length;
    const bashCount = s.bashPatterns.length;
    const importCount = s.importPatterns.length;
    lines.push(`| \`${s.slug}\` | ${s.priority} | ${pathCount} | ${bashCount} | ${importCount} |`);
  }
  lines.push("");

  // Detail for each skill
  lines.push("### Skill Details");
  lines.push("");

  for (const s of skills) {
    lines.push(`#### \`${s.slug}\` (priority ${s.priority})`);
    lines.push("");

    if (s.pathPatterns.length > 0) {
      lines.push("**Path patterns:**");
      for (const p of s.pathPatterns) {
        lines.push(`- \`${p}\``);
      }
      lines.push("");
    }

    if (s.bashPatterns.length > 0) {
      lines.push("**Bash patterns:**");
      for (const p of s.bashPatterns) {
        lines.push(`- \`${p}\``);
      }
      lines.push("");
    }

    if (s.importPatterns.length > 0) {
      lines.push("**Import patterns:**");
      for (const p of s.importPatterns) {
        lines.push(`- \`${p}\``);
      }
      lines.push("");
    }

    // Find example matches from overlap targets
    const pathMatches = OVERLAP_TARGETS.filter((t) => matchesPath(s, t));
    const bashMatches = BASH_OVERLAP_TARGETS.filter((t) => matchesBash(s, t));

    if (pathMatches.length > 0 || bashMatches.length > 0) {
      lines.push("**Matched examples:**");
      for (const m of pathMatches) lines.push(`- \`${m}\` (path)`);
      for (const m of bashMatches) lines.push(`- \`${m}\` (bash)`);
      lines.push("");
    }
  }

  // Path overlap matrix
  lines.push("## Path Overlap Matrix");
  lines.push("");
  lines.push("Shows which skills compete on shared file targets.");
  lines.push("");

  const pathOverlaps: { target: string; skills: string[] }[] = [];
  for (const target of OVERLAP_TARGETS) {
    const matching = skills.filter((s) => matchesPath(s, target)).map((s) => s.slug);
    if (matching.length >= 2) {
      pathOverlaps.push({ target, skills: matching });
    }
  }

  if (pathOverlaps.length === 0) {
    lines.push("No path overlaps detected among tested targets.");
  } else {
    lines.push("| Target File | Competing Skills (priority) |");
    lines.push("|-------------|---------------------------|");
    for (const { target, skills: slugs } of pathOverlaps) {
      const detail = slugs.map((slug) => {
        const s = skills.find((sk) => sk.slug === slug)!;
        return `\`${slug}\` (${s.priority})`;
      }).join(", ");
      lines.push(`| \`${target}\` | ${detail} |`);
    }
  }
  lines.push("");

  // Bash overlap matrix
  lines.push("## Bash Overlap Matrix");
  lines.push("");
  lines.push("Shows which skills compete on shared bash commands.");
  lines.push("");

  const bashOverlaps: { target: string; skills: string[] }[] = [];
  for (const target of BASH_OVERLAP_TARGETS) {
    const matching = skills.filter((s) => matchesBash(s, target)).map((s) => s.slug);
    if (matching.length >= 2) {
      bashOverlaps.push({ target, skills: matching });
    }
  }

  if (bashOverlaps.length === 0) {
    lines.push("No bash overlaps detected among tested commands.");
  } else {
    lines.push("| Bash Command | Competing Skills (priority) |");
    lines.push("|--------------|---------------------------|");
    for (const { target, skills: slugs } of bashOverlaps) {
      const detail = slugs.map((slug) => {
        const s = skills.find((sk) => sk.slug === slug)!;
        return `\`${slug}\` (${s.priority})`;
      }).join(", ");
      lines.push(`| \`${target}\` | ${detail} |`);
    }
  }
  lines.push("");

  // Skills by priority
  lines.push("## Skills by Priority");
  lines.push("");

  const byPriority = new Map<number, string[]>();
  for (const s of skills) {
    const list = byPriority.get(s.priority) ?? [];
    list.push(s.slug);
    byPriority.set(s.priority, list);
  }

  for (const [pri, slugs] of [...byPriority.entries()].sort((a, b) => b[0] - a[0])) {
    lines.push(`**Priority ${pri}:** ${slugs.map((s) => `\`${s}\``).join(", ")}`);
    lines.push("");
  }

  // Write output
  const outputDir = join(ROOT, "generated");
  try {
    await stat(outputDir);
  } catch {
    await mkdir(outputDir, { recursive: true });
  }

  const content = lines.join("\n") + "\n";
  await writeFile(OUTPUT_PATH, content);
  console.log(`Wrote ${OUTPUT_PATH} (${skills.length} skills, ${pathOverlaps.length} path overlaps, ${bashOverlaps.length} bash overlaps)`);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
