// engine/design-to-spec/ac-generator.ts — Generate acceptance criteria from parsed design (SPEC-159)
// ---------------------------------------------------------------------------
// A11y AC templates (WCAG 2.1 AA)
// ---------------------------------------------------------------------------
const A11Y_TEMPLATES = [
    'All interactive elements are keyboard accessible (Tab, Enter, Space)',
    'All images have descriptive alt text or are marked as decorative (alt="")',
    'Color contrast ratio meets WCAG 2.1 AA (≥ 4.5:1 for normal text, ≥ 3:1 for large text)',
    'Form fields have associated labels (visible or via aria-label)',
    'Error messages are programmatically associated with their fields (aria-describedby)',
    'Page has a logical heading hierarchy (h1 → h2 → h3)',
    'Focus is visible and never lost during interactions',
    'Screen reader announces dynamic content updates (aria-live regions)',
];
const A11Y_BY_COMPONENT_TYPE = {
    button: [
        'Button has accessible name (label text or aria-label)',
        'Disabled buttons communicate state to screen readers (aria-disabled)',
    ],
    input: [
        'Input field has a visible label or aria-label',
        'Required fields are marked with aria-required="true"',
        'Validation errors are announced to screen readers',
    ],
    modal: [
        'Modal traps focus when open; returns focus to trigger on close',
        'Modal has role="dialog" and aria-modal="true"',
        'Pressing Escape closes the modal',
    ],
    nav: [
        'Navigation has a landmark role (role="navigation" or <nav>)',
        'Current page/item is indicated via aria-current',
    ],
    list: [
        'List uses semantic <ul>/<ol>/<li> or appropriate ARIA list roles',
        'Empty state is announced to screen readers',
    ],
    form: [
        'Form has a clear submit mechanism accessible via keyboard',
        'All required fields are indicated (asterisk + aria-required)',
    ],
    image: ['Informative images have descriptive alt text', 'Decorative images use alt=""'],
    card: ['Card interactive area has an accessible name describing its action'],
    text: [],
    container: [],
    other: [],
};
// ---------------------------------------------------------------------------
// AC generators per screen/component
// ---------------------------------------------------------------------------
/** Generate ACs for a specific component */
function generateComponentAcs(component, screenName) {
    const acs = [];
    const ctx = `${screenName} > ${component.name}`;
    // Visibility AC
    acs.push(`${ctx} is visible and rendered correctly on first load`);
    // Interaction state ACs
    for (const state of component.interactionStates) {
        if (state.name !== 'default') {
            acs.push(`${ctx} shows ${state.name} state when ${state.trigger.toLowerCase()}`);
        }
    }
    // Type-specific ACs
    switch (component.type) {
        case 'form':
            acs.push(`${ctx} validates all required fields before submission`);
            acs.push(`${ctx} shows inline error messages for invalid fields`);
            acs.push(`${ctx} shows success feedback after successful submission`);
            break;
        case 'button':
            acs.push(`${ctx} is disabled and non-interactive when loading is in progress`);
            break;
        case 'input':
            acs.push(`${ctx} accepts valid input and rejects invalid input with a clear error message`);
            break;
        case 'list':
            acs.push(`${ctx} shows an empty state message when there are no items`);
            acs.push(`${ctx} shows a loading skeleton while data is being fetched`);
            break;
        case 'modal':
            acs.push(`${ctx} opens when its trigger is activated`);
            acs.push(`${ctx} closes when the user clicks outside or presses Escape`);
            break;
        case 'nav':
        case 'card':
        case 'text':
        case 'image':
        case 'container':
        case 'other':
            break;
    }
    return acs;
}
/** Generate ACs for data bindings on a screen */
function generateDataBindingAcs(screenName, dataSource) {
    return [
        `${screenName}: Data from "${dataSource}" loads successfully within 2 seconds`,
        `${screenName}: A loading indicator is shown while "${dataSource}" data is being fetched`,
        `${screenName}: An error state is shown if "${dataSource}" data fails to load`,
        `${screenName}: Stale data is refreshed when the user returns to the screen`,
    ];
}
/** Generate platform-specific ACs */
function generatePlatformAcs(screenName, platform) {
    const acs = [];
    switch (platform) {
        case 'web':
            acs.push(`${screenName}: Layout adapts correctly at mobile (< 768px), tablet (768–1023px), and desktop (≥ 1024px) breakpoints`);
            acs.push(`${screenName}: Page title is set correctly for SEO and screen reader context`);
            break;
        case 'mobile':
            acs.push(`${screenName}: Touch targets are at least 44 × 44 pt (iOS) / 48 × 48 dp (Android)`);
            acs.push(`${screenName}: Screen works correctly in both portrait and landscape orientations`);
            break;
        case 'desktop':
            acs.push(`${screenName}: Keyboard shortcuts are discoverable and functional`);
            acs.push(`${screenName}: Layout uses available horizontal space efficiently`);
            break;
    }
    return acs;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Generates acceptance criteria for a single screen.
 * Returns ACs grouped by theme: visibility, interactions, data, a11y, platform.
 */
export function generateAcsForScreen(screen, platform, includeA11y) {
    const acs = [];
    // Screen-level ACs
    acs.push(`${screen.name} renders without layout errors on first load`);
    acs.push(`${screen.name} is accessible via its defined route: ${screen.route ?? '(route TBD)'}`);
    // Component-level ACs
    for (const component of screen.components) {
        acs.push(...generateComponentAcs(component, screen.name));
    }
    // Data binding ACs
    for (const binding of screen.dataBindings) {
        acs.push(...generateDataBindingAcs(screen.name, binding.dataSource));
    }
    // Platform ACs
    acs.push(...generatePlatformAcs(screen.name, platform));
    // A11y ACs
    if (includeA11y) {
        acs.push(...A11Y_TEMPLATES.map((t) => `${screen.name}: ${t}`));
        for (const component of screen.components) {
            const typeAcs = A11Y_BY_COMPONENT_TYPE[component.type];
            acs.push(...typeAcs.map((t) => `${screen.name} > ${component.name}: ${t}`));
        }
    }
    return acs;
}
/**
 * Generates all acceptance criteria for a set of screens.
 * Returns a deduplicated flat array of AC strings.
 */
export function generateAllAcs(screens, platform, includeA11y) {
    const seen = new Set();
    const result = [];
    for (const screen of screens) {
        const screenAcs = generateAcsForScreen(screen, platform, includeA11y);
        for (const ac of screenAcs) {
            if (!seen.has(ac)) {
                seen.add(ac);
                result.push(ac);
            }
        }
    }
    return result;
}
/**
 * Returns a11y requirements for a component type.
 * Used by ui-contract-builder to annotate component entries.
 */
export function getA11yRequirementsForComponent(componentType) {
    return A11Y_BY_COMPONENT_TYPE[componentType];
}
/**
 * Returns global a11y requirements that apply to every screen.
 */
export function getGlobalA11yRequirements() {
    return [...A11Y_TEMPLATES];
}
//# sourceMappingURL=ac-generator.js.map