// tools/define-ui-contract/css-styling-contract.ts — Styling Contract + UX Principles (SPEC-017a)
// Generates framework-specific styling contracts and UX principles.
import { readFile } from 'node:fs/promises';
// === Config loaders (lazy, cached) ===
let uxCache = null;
let frameworkCatalogCache = null;
/** Reset module-level caches — for testing purposes only. */
export function resetCaches() {
    uxCache = null;
    frameworkCatalogCache = null;
}
async function loadUXPrinciples() {
    if (uxCache !== null) {
        return uxCache;
    }
    try {
        const configPath = new URL('../../config/ux-principles.json', import.meta.url);
        const raw = await readFile(configPath, 'utf-8');
        const data = JSON.parse(raw);
        uxCache = data.principles.map((p) => ({
            category: p.category,
            title: p.title,
            rules: p.rules,
            examples: p.examples,
            applicableTo: p.applicableTo,
        }));
        return uxCache;
    }
    catch {
        uxCache = [];
        return uxCache;
    }
}
async function loadFrameworkConfig(framework) {
    /* v8 ignore start */ // cache false-branch is runtime-only (cache hit after first load)
    if (frameworkCatalogCache === null) {
        /* v8 ignore stop */
        try {
            const configPath = new URL('../../config/ui-frameworks.json', import.meta.url);
            const raw = await readFile(configPath, 'utf-8');
            const parsed = JSON.parse(raw);
            // Build typed catalog — exclude _description key
            const catalog = {};
            for (const [key, value] of Object.entries(parsed)) {
                /* v8 ignore start */ // _description key filter — depends on config file structure
                if (key !== '_description' && typeof value === 'object') {
                    catalog[key] = value; /* v8 ignore stop */
                }
            }
            frameworkCatalogCache = catalog;
        }
        catch {
            frameworkCatalogCache = {};
        }
    }
    return frameworkCatalogCache[framework] ?? null;
}
// === Public API ===
/**
 * Generate a Styling Contract adapted to the detected CSS framework.
 */
export async function generateStylingContract(detection) {
    const { framework } = detection;
    if (!framework) {
        return {
            framework: null,
            conventions: [
                'No CSS framework detected.',
                'Consider adopting Tailwind CSS or shadcn/ui for consistency.',
            ],
        };
    }
    const config = await loadFrameworkConfig(framework);
    if (!config) {
        return { framework };
    }
    return {
        framework,
        conventions: config.conventions,
        components: config.components,
        breakpoints: config.breakpoints,
        darkMode: config.darkMode,
        responsive: config.responsive,
        /* v8 ignore start */ // empty-plugins branch is framework-config dependent
        plugins: config.plugins?.length ? config.plugins : undefined /* v8 ignore stop */,
    };
}
/**
 * Generate UX Principles applicable to the given project context.
 * Always includes all universal principles.
 */
export async function generateUXPrinciples(projectContext) {
    const all = await loadUXPrinciples();
    if (all.length === 0) {
        return getBuiltinUXPrinciples();
    }
    // Include principles applicable to the context or with no restriction
    return all.filter((p) => {
        /* v8 ignore start */ // branch depends on ux-principles.json content which varies
        if (!p.applicableTo || p.applicableTo.length === 0) {
            return true; /* v8 ignore stop */
        }
        return p.applicableTo.includes(projectContext) || p.applicableTo.includes('web');
    });
}
// === Format functions ===
/**
 * Format Styling Contract as Markdown for inclusion in UI contract output.
 */
export function formatStylingContract(contract) {
    const lines = ['## Styling Contract'];
    if (!contract.framework) {
        lines.push('');
        lines.push('> No CSS framework detected. Consider adopting one for consistency.');
        if (contract.conventions) {
            for (const c of contract.conventions) {
                lines.push(`- ${c}`);
            }
        }
        return lines.join('\n');
    }
    lines.push('');
    lines.push(`**Framework:** ${contract.framework}`);
    if (contract.responsive) {
        lines.push('');
        lines.push(`**Responsive Strategy:** ${contract.responsive}`);
    }
    if (contract.darkMode) {
        lines.push(`**Dark Mode:** ${contract.darkMode}`);
    }
    if (contract.breakpoints && Object.keys(contract.breakpoints).length > 0) {
        lines.push('');
        lines.push('### Breakpoints');
        lines.push('');
        lines.push('| Name | Width |');
        lines.push('|------|-------|');
        for (const [name, width] of Object.entries(contract.breakpoints)) {
            lines.push(`| ${name} | ${width} |`);
        }
    }
    if (contract.conventions && contract.conventions.length > 0) {
        lines.push('');
        lines.push('### Conventions');
        lines.push('');
        for (const c of contract.conventions) {
            lines.push(`- ${c}`);
        }
    }
    /* v8 ignore next 7 */ // components list only present for specific frameworks
    if (contract.components && contract.components.length > 0) {
        lines.push('');
        lines.push('### Available Components');
        lines.push('');
        for (const c of contract.components) {
            lines.push(`- ${c}`);
        }
    }
    if (contract.plugins && contract.plugins.length > 0) {
        lines.push('');
        lines.push('### Common Plugins');
        lines.push('');
        for (const p of contract.plugins) {
            lines.push(`- \`${p}\``);
        }
    }
    return lines.join('\n');
}
/**
 * Format UX Principles as Markdown.
 */
export function formatUXPrinciples(principles) {
    if (principles.length === 0) {
        return '## UX Principles\n\n> No UX principles loaded.';
    }
    const lines = ['## UX Principles'];
    lines.push('');
    for (const p of principles) {
        lines.push(`### ${p.category} — ${p.title}`);
        lines.push('');
        for (const rule of p.rules) {
            lines.push(`- ${rule}`);
        }
        if (p.examples && p.examples.length > 0) {
            lines.push('');
            lines.push('**Examples:**');
            for (const ex of p.examples) {
                lines.push(`- \`${ex}\``);
            }
        }
        lines.push('');
    }
    return lines.join('\n');
}
// === Builtin fallback UX principles (when config file unavailable) ===
function getBuiltinUXPrinciples() {
    return [
        {
            category: 'Accessibility (WCAG 2.1 AA)',
            title: 'Core Requirements',
            rules: [
                'All interactive elements keyboard accessible',
                'Visible focus indicator on all focusable elements',
                'Color contrast: 4.5:1 for normal text, 3:1 for large text',
                'Images have alt text; decorative images use alt=""',
            ],
        },
        {
            category: 'Responsive Design',
            title: 'Mobile-First',
            rules: [
                'Minimum touch target: 48x48px',
                'Mobile-first breakpoints with min-width media queries',
                'No horizontal scrolling at 320px viewport width',
            ],
        },
        {
            category: 'Performance UX',
            title: 'Perceived Performance',
            rules: [
                'Skeleton screens during loading — not spinners only',
                'Optimistic updates for immediate feedback',
                'Lazy load below-the-fold content',
            ],
        },
    ];
}
//# sourceMappingURL=css-styling-contract.js.map