/**
 * Design System Registry — 150+ Curated Systems from Open Design
 *
 * Design systems are stored as DESIGN.md + tokens.css files under
 * data/systems/<name>/. At import time, we scan the directory and
 * parse each system's metadata (name, category, description) from
 * the DESIGN.md frontmatter. Full content is lazily loaded on first
 * access and cached.
 *
 * The tool interface remains the same as the original systems.ts:
 *   findSystem(name)  → DesignSystem | undefined
 *   formatSystemForLLM(system) → string
 *   listSystemsForLLM() → string
 */
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
// ---------------------------------------------------------------------------
// Discovery — build the registry from data/systems/
// ---------------------------------------------------------------------------
/** The directory containing design system data. We try multiple paths to
 *  handle both dev (src/) and production (dist/) layouts. */
function discoverDataDir() {
    // Production: __dirname is dist/designer/, data is dist/designer/data/systems/
    const prodPath = resolve(__dirname, "data", "systems");
    if (existsSync(prodPath))
        return prodPath;
    // Standalone binary: check relative to the executable (Bun compile)
    const execDir = dirname(process.execPath);
    const standalonePath = resolve(execDir, "data", "systems");
    if (existsSync(standalonePath))
        return standalonePath;
    // Both dev (src/designer/) and production (dist/designer/) layouts resolve the same way
    return prodPath;
}
function parseCategory(line) {
    const m = /Category:\s*(.+)/i.exec(line);
    return m ? m[1].trim() : "Uncategorised";
}
function parseName(h1) {
    return h1
        .replace(/^#\s*Design System Inspired by\s*/i, "")
        .replace(/^#\s*/i, "")
        .trim();
}
function parseDescription(lines) {
    // Take the first non-empty, non-heading, non-bracket line after the header
    for (const line of lines) {
        const trimmed = line.trim();
        if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith(">"))
            continue;
        // Take up to 120 chars for the description
        return trimmed.length > 120 ? trimmed.slice(0, 117) + "..." : trimmed;
    }
    return "Design system from the Open Design registry.";
}
function buildRegistry() {
    const map = new Map();
    const baseDir = discoverDataDir();
    if (!existsSync(baseDir)) {
        process.stderr.write(`[designer] Design system data directory not found at ${baseDir}\n`);
        return map;
    }
    let entries;
    try {
        entries = readdirSync(baseDir, { withFileTypes: true })
            .filter((d) => d.isDirectory())
            .map((d) => d.name);
    }
    catch {
        process.stderr.write(`[designer] Cannot read design system directory ${baseDir}\n`);
        return map;
    }
    for (const name of entries) {
        const dir = resolve(baseDir, name);
        const mdPath = resolve(dir, "DESIGN.md");
        const cssPath = resolve(dir, "tokens.css");
        if (!existsSync(mdPath))
            continue;
        let designMd;
        try {
            designMd = readFileSync(mdPath, "utf-8");
        }
        catch {
            continue;
        }
        const mdLines = designMd.split("\n");
        // Extract metadata from the first heading lines
        let h1Line = "";
        let categoryLine = "";
        const bodyLines = [];
        for (const line of mdLines) {
            const t = line.trim();
            if (!h1Line && t.startsWith("# "))
                h1Line = t;
            else if (!categoryLine && t.startsWith("> Category:"))
                categoryLine = t;
            else
                bodyLines.push(line);
        }
        const parsedName = parseName(h1Line || `# ${name}`);
        const category = parseCategory(categoryLine);
        const description = parseDescription(bodyLines);
        let tokensCss = "";
        if (existsSync(cssPath)) {
            try {
                tokensCss = readFileSync(cssPath, "utf-8");
            }
            catch {
                // tokens optional
            }
        }
        let componentsHtml = "";
        const compPath = resolve(dir, "components.html");
        if (existsSync(compPath)) {
            try {
                componentsHtml = readFileSync(compPath, "utf-8");
            }
            catch {
                // components optional
            }
        }
        map.set(parsedName.toLowerCase(), {
            name: parsedName,
            category,
            description,
            designMd,
            tokensCss,
            componentsHtml,
        });
    }
    return map;
}
// ---------------------------------------------------------------------------
// Registry singleton
// ---------------------------------------------------------------------------
let _registry = null;
function registry() {
    if (!_registry)
        _registry = buildRegistry();
    return _registry;
}
// ---------------------------------------------------------------------------
// Lookup
// ---------------------------------------------------------------------------
export function findSystem(name) {
    const lower = name.toLowerCase().trim();
    const reg = registry();
    // Exact match
    if (reg.has(lower))
        return reg.get(lower);
    // Prefix / fuzzy match
    for (const [key, sys] of reg) {
        if (key.startsWith(lower) || key.includes(lower))
            return sys;
    }
    return undefined;
}
// ---------------------------------------------------------------------------
// LLM formatters
// ---------------------------------------------------------------------------
/**
 * Format a single design system for the LLM.
 * Concatenates the DESIGN.md and tokens.css for a complete picture.
 */
export function formatSystemForLLM(system) {
    const parts = [system.designMd];
    if (system.tokensCss) {
        parts.push("\n---\n## CSS Custom Properties (tokens.css)\n");
        parts.push("```css");
        parts.push(system.tokensCss);
        parts.push("```");
    }
    if (system.componentsHtml) {
        parts.push("\n---\n## Component Examples (components.html)\n");
        parts.push(system.componentsHtml);
    }
    parts.push("\n---\n", "## How to Use This System\n", "1. Copy the `:root { ... }` block from tokens.css into your `<style>` block.", "2. Reference tokens as `var(--bg)`, `var(--fg)`, `var(--accent)`, `var(--font-body)`, etc.", "3. Follow the component styling guidelines from the DESIGN.md sections.", "4. Use the component examples as concrete starting points — adapt colors and fonts to the active design system.", "5. Apply typography rules: font families, sizes, and line-heights from the tokens.");
    return parts.join("\n");
}
/**
 * List all available design systems as a compact markdown table for the LLM.
 */
export function listSystemsForLLM() {
    const reg = registry();
    const all = [...reg.values()];
    // Group by category
    const byCategory = new Map();
    for (const sys of all) {
        const cat = sys.category;
        if (!byCategory.has(cat))
            byCategory.set(cat, []);
        byCategory.get(cat).push(sys);
    }
    const lines = [
        `# Available Design Systems (${all.length} total)`,
        "",
        "Grouped by category. Use `designer_get_system` with the system **name** to load full tokens and guidelines.",
        "",
    ];
    for (const [category, systems] of [...byCategory].sort((a, b) => a[0].localeCompare(b[0]))) {
        systems.sort((a, b) => a.name.localeCompare(b.name));
        lines.push(`## ${category}`);
        lines.push("");
        for (const s of systems) {
            lines.push(`- **${s.name}** — ${s.description}`);
        }
        lines.push("");
    }
    // Quick-select list at the end
    lines.push("---");
    lines.push("");
    lines.push("Quick reference (all system names, one per line):");
    lines.push("");
    const sorted = [...all].sort((a, b) => a.name.localeCompare(b.name));
    for (const s of sorted) {
        lines.push(`- ${s.name}`);
    }
    return lines.join("\n");
}
