/**
 * GET /skills.json — the palette + (legacy) skill grid data source.
 *
 * v1 served a cached file generated by scripts/regenerate.ts. v2 builds
 * this live by walking the installed plugins discovered in agent.ts.
 *
 * Shape (preserved exactly):
 *   { hop: [{name, desc}, ...], pm: { "Toolkit": [...], "Product Strategy": [...], ... } }
 */
import type { Hono } from "hono";
import { readFileSync, readdirSync, statSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { INSTALLED_PLUGINS } from "./agent";

type Skill = { name: string; desc: string };

/** Flat skill record used by /api/skills/all (slash menu, search). */
export type AllSkill = { name: string; desc: string; source: string };

/** Read SKILL.md frontmatter and extract { name, description }. */
function parseSkillMd(file: string): Skill | null {
  let text: string;
  try { text = readFileSync(file, "utf8"); } catch { return null; }
  const fm = text.match(/^---\s*\n([\s\S]*?)\n---/);
  if (!fm) return null;
  const name = fm[1].match(/^name:\s*(.+?)\s*$/m)?.[1]?.trim();
  let desc = fm[1].match(/^description:\s*([\s\S]+?)(?:\n\w+:|$)/m)?.[1]?.trim();
  if (!name || !desc) return null;
  // strip wrapping quotes if present
  if ((desc.startsWith('"') && desc.endsWith('"')) || (desc.startsWith("'") && desc.endsWith("'"))) {
    desc = desc.slice(1, -1);
  }
  return { name, desc: desc.replace(/\s+/g, " ").trim() };
}

/** Walk a plugin's `skills/` dir and collect all SKILL.md entries. */
function loadPluginSkills(pluginPath: string): Skill[] {
  const skillsDir = join(pluginPath, "skills");
  let entries: string[] = [];
  try { entries = readdirSync(skillsDir); } catch { return []; }
  const out: Skill[] = [];
  for (const name of entries) {
    const skillFile = join(skillsDir, name, "SKILL.md");
    try {
      if (!statSync(skillFile).isFile()) continue;
    } catch { continue; }
    const s = parseSkillMd(skillFile);
    if (s) out.push(s);
  }
  return out.sort((a, b) => a.name.localeCompare(b.name));
}

/** Plugin → bucket label for the UI. Anything unmapped lives under "Other". */
const PM_BUCKETS: Record<string, string> = {
  "pm-toolkit": "Toolkit",
  "pm-product-strategy": "Product Strategy",
  "pm-product-discovery": "Product Discovery",
  "pm-market-research": "Market Research",
  "pm-data-analytics": "Data & Analytics",
  "pm-marketing-growth": "Marketing & Growth",
  "pm-go-to-market": "Go-To-Market",
  "pm-execution": "Execution",
};

export type SkillsBundle = { hop: Skill[]; pm: Record<string, Skill[]> };

function buildSkillsBundle(): SkillsBundle {
  const hop: Skill[] = [];
  const pm: Record<string, Skill[]> = {};

  for (const p of INSTALLED_PLUGINS) {
    // Plugin name = the leaf dir of the install path (excluding the version segment).
    // e.g. .../cache/pm-skills/pm-toolkit/1.0.1 → "pm-toolkit"
    const parts = p.path.split("/");
    const pluginName = parts[parts.length - 2] || parts[parts.length - 1];
    const skills = loadPluginSkills(p.path);
    if (!skills.length) continue;

    if (pluginName === "head-of-product") {
      hop.push(...skills);
    } else if (PM_BUCKETS[pluginName]) {
      pm[PM_BUCKETS[pluginName]] = (pm[PM_BUCKETS[pluginName]] || []).concat(skills);
    }
    // Other plugins (claude-md-management, posthog, etc.) are not surfaced
    // in the legacy skill grid — they're available via the palette / Skill
    // tool inside chat regardless.
  }

  return { hop, pm };
}

/** Walk `~/.claude/skills/` (user-level skills, no plugin packaging). */
function loadUserSkills(): Skill[] {
  const dir = join(homedir(), ".claude", "skills");
  let entries: string[] = [];
  try { entries = readdirSync(dir); } catch { return []; }
  const out: Skill[] = [];
  for (const name of entries) {
    const skillFile = join(dir, name, "SKILL.md");
    try {
      if (!statSync(skillFile).isFile()) continue;
    } catch { continue; }
    const s = parseSkillMd(skillFile);
    if (s) out.push(s);
  }
  return out.sort((a, b) => a.name.localeCompare(b.name));
}

/** Flat list of every invokable skill: plugins + ~/.claude/skills/. */
function buildAllSkills(): AllSkill[] {
  const seen = new Set<string>();
  const out: AllSkill[] = [];
  const push = (s: Skill, source: string) => {
    if (seen.has(s.name)) return;
    seen.add(s.name);
    out.push({ name: s.name, desc: s.desc, source });
  };

  for (const p of INSTALLED_PLUGINS) {
    const parts = p.path.split("/");
    const pluginName = parts[parts.length - 2] || parts[parts.length - 1];
    for (const s of loadPluginSkills(p.path)) push(s, pluginName);
  }
  for (const s of loadUserSkills()) push(s, "user");

  return out.sort((a, b) => a.name.localeCompare(b.name));
}

export function registerSkillsRoutes(app: Hono) {
  let cached: SkillsBundle | null = null;
  let cachedAll: AllSkill[] | null = null;
  app.get("/skills.json", (c) => {
    if (!cached) cached = buildSkillsBundle();
    return c.json(cached);
  });
  app.get("/api/skills/all", (c) => {
    if (!cachedAll) cachedAll = buildAllSkills();
    return c.json(cachedAll);
  });
}
