"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadDesignSystemMarkdown = exports.getDesignSystemBySlug = exports.rankDesignSystemsForPrompt = exports.DESIGN_SYSTEMS = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
/**
 * Curated catalog of design-system inspirations bundled as DESIGN.md files
 * under `src/services/templates/designmd/`. The MCP agent-variants fresh-
 * project flow ranks these against the user's prompt and pins one per variant
 * slot; the matching DESIGN.md is copied into each scaffolded worktree so each
 * variant has a concrete visual direction.
 *
 * Source of truth for both the MCP server and the desktop "create app" flow.
 * Desktop re-exports from this module via `desktop/main/CreateAppCatalog.ts`.
 */
const WORD_SPLIT_RE = /[^a-z0-9]+/i;
const MARKDOWN_SHAPE_RE = /^(#|---|\*\*|[A-Za-z0-9][^\n]*\n#{1,3}\s)/;
// Resolved relative to this file at runtime. The `designmd/` directory must
// sit next to the compiled module in `dist/` as well — `tsc` does not copy
// non-`.ts` files, so the project's build script has a dedicated
// `build:assets` step that mirrors `src/services/templates/designmd/*.md`
// into `dist/services/templates/designmd/`. Without that mirror the catalog
// silently loads empty and `createZeroToOneTool` produces empty slugs.
const designMdDir = path_1.default.resolve(__dirname, 'designmd');
const DESIGN_MD_BY_SLUG = new Map();
const toDisplayName = (slug) => slug
    .replace(/[._-]+/g, ' ')
    .split(/\s+/)
    .filter(Boolean)
    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
    .join(' ');
const stripFrontmatter = (markdown) => {
    if (!markdown.startsWith('---\n')) {
        return markdown;
    }
    const frontmatterEnd = markdown.indexOf('\n---\n', 4);
    if (frontmatterEnd === -1) {
        return markdown;
    }
    return markdown.slice(frontmatterEnd + 5);
};
const parseDescription = (markdown) => {
    const markdownBody = stripFrontmatter(markdown).trim();
    const firstParagraph = markdownBody.split(/\n\s*\n/)[0] ?? '';
    return firstParagraph.replace(/\s+/g, ' ').trim().slice(0, 220);
};
const buildKeywords = (slug) => {
    const slugWords = slug
        .toLowerCase()
        .split(/[^a-z0-9]+/)
        .filter(Boolean);
    return Array.from(new Set([slug.toLowerCase(), ...slugWords]));
};
const loadDesignSystems = () => {
    let entries;
    try {
        entries = fs_1.default.readdirSync(designMdDir, { withFileTypes: true });
    }
    catch {
        return [];
    }
    // Defensive: if the test or runtime mock returns a non-array, skip
    // catalog initialization rather than crashing module load.
    if (!Array.isArray(entries))
        return [];
    return entries
        .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
        .map((entry) => entry.name)
        .sort((first, second) => first.localeCompare(second))
        .map((filename) => {
        const slug = filename.slice(0, -3);
        const markdownPath = path_1.default.resolve(designMdDir, filename);
        const markdown = fs_1.default.readFileSync(markdownPath, 'utf8').trim();
        if (!markdown) {
            throw new Error(`Empty DESIGN.md for slug "${slug}"`);
        }
        if (!MARKDOWN_SHAPE_RE.test(markdown)) {
            throw new Error(`Invalid markdown shape for slug "${slug}"`);
        }
        DESIGN_MD_BY_SLUG.set(slug, markdown);
        const name = toDisplayName(slug);
        const description = parseDescription(markdown);
        return {
            slug,
            name,
            category: 'Design System',
            description: description || `Design system for ${name}`,
            keywords: buildKeywords(slug),
            externalUrl: `https://getdesign.md/${slug}/design-md`,
        };
    });
};
exports.DESIGN_SYSTEMS = loadDesignSystems();
const normalizeWords = (text) => text
    .toLowerCase()
    .split(WORD_SPLIT_RE)
    .map((word) => word.trim())
    .filter((word) => word.length > 1);
const scoreDesignSystem = (promptWords, designSystem) => {
    const textWords = normalizeWords(`${designSystem.name} ${designSystem.category} ${designSystem.description}`);
    return textWords.reduce((score, word) => (promptWords.has(word) ? score + 1 : score), 0);
};
/**
 * Rank bundled DESIGN.md inspirations against a user prompt. Deterministic for
 * a given prompt: ties broken by catalog index (alphabetical slug order).
 */
const rankDesignSystemsForPrompt = (prompt, limit = 3) => {
    const promptWords = new Set(normalizeWords(prompt));
    return exports.DESIGN_SYSTEMS.map((designSystem, index) => ({
        ...designSystem,
        score: scoreDesignSystem(promptWords, designSystem),
        index,
    }))
        .sort((a, b) => {
        if (b.score !== a.score)
            return b.score - a.score;
        return a.index - b.index;
    })
        .slice(0, limit)
        .map(({ index: _index, ...designSystem }) => designSystem);
};
exports.rankDesignSystemsForPrompt = rankDesignSystemsForPrompt;
/**
 * Resolve a catalog entry by slug. Returns null if the slug is unknown.
 */
const getDesignSystemBySlug = (slug) => {
    return exports.DESIGN_SYSTEMS.find((entry) => entry.slug === slug) ?? null;
};
exports.getDesignSystemBySlug = getDesignSystemBySlug;
/**
 * Read the bundled DESIGN.md markdown for a slug. Returns null when the slug
 * is unknown.
 */
const loadDesignSystemMarkdown = (slug) => {
    return DESIGN_MD_BY_SLUG.get(slug) ?? null;
};
exports.loadDesignSystemMarkdown = loadDesignSystemMarkdown;
//# sourceMappingURL=designCatalog.js.map