// tools/define-ui-contract.ts — UI contract & component tree
// Analyzes a spec to generate component trees, data flow definitions,
// loading states, and error states for frontend implementation.
import { readFile } from 'node:fs/promises';
import { specStore, knowledgeStore } from '../storage/index.js';
import { t, ti } from '../i18n/index.js';
import { isMobileFramework, generateMobileUIContract } from './define-ui-contract-mobile.js';
import { generateComponentTree, generateDataFlow, generateLoadingStates, generateErrorStates, } from './define-ui-contract-web.js';
import { isGameProject, generateGameUIContract } from './define-ui-contract-games.js';
import { isDesktopProject, generateDesktopUIContract } from './define-ui-contract-desktop.js';
import { isExtensionProject, generateExtensionUIContract, } from './define-ui-contract-extensions.js';
import { isMcpToolContract, formatMcpToolContractAsMarkdown, } from './create-spec/mcp-tool-contract.js';
import { detectCSSFramework } from '../engine/detectors/css-framework-detector.js';
import { generateStylingContract, generateUXPrinciples, formatStylingContract, formatUXPrinciples, } from './define-ui-contract/css-styling-contract.js';
import { generateA11yContract, detectA11yLevel, formatA11yContract, } from './define-ui-contract/a11y-contract.js';
export async function handleDefineUIContract(args) {
    const { specId, projectId, screens } = args;
    // 1. Load spec
    const spec = await specStore.getSpec(projectId, specId);
    if (!spec) {
        return {
            content: [{ type: 'text', text: ti('spec.notFound', { id: specId }) }],
            isError: true,
        };
    }
    // 2. Check spec has frontend relevance
    if (spec.target === 'backend' || spec.target === 'database' || spec.target === 'infrastructure') {
        // SPEC-016b: MCP servers are backend but still need Tool Contracts — load knowledge first
        const knowledgeCheck = await knowledgeStore.getKnowledge(projectId);
        if (!isMcpToolContract(knowledgeCheck)) {
            return {
                content: [
                    {
                        type: 'text',
                        text: `Spec "${spec.title}" targets "${spec.target}" which has no UI components. Change spec target to "frontend" or "fullstack" to generate UI contracts.`,
                    },
                ],
                isError: true,
            };
        }
    }
    // 3. Load project knowledge
    const knowledge = await knowledgeStore.getKnowledge(projectId);
    if (!knowledge) {
        return {
            content: [{ type: 'text', text: t('project.notFound') }],
            isError: true,
        };
    }
    // SPEC-016b: MCP servers produce Tool Contracts (not UI contracts)
    if (isMcpToolContract(knowledge)) {
        const detectedScreens = screens ?? [spec.title];
        const tools = detectedScreens.map((s) => ({
            name: s.toLowerCase().replace(/[^a-z0-9]/g, '_'),
            description: `MCP tool for ${s}`,
            fields: ['input'],
        }));
        return {
            content: [
                {
                    type: 'text',
                    text: ti('tools.define_ui_contract.success', { componentCount: String(tools.length) }),
                },
                {
                    type: 'text',
                    text: formatMcpToolContractAsMarkdown(tools, knowledge),
                },
            ],
        };
    }
    // 4. Read spec content
    const specContent = await readSpecContent(spec);
    // 5. Extract screen/component references
    const detectedScreens = screens ?? extractScreens(specContent);
    // 5b. Mobile UI contract shortcut — SwiftUI / UIKit / Compose / XML
    if (isMobileFramework(knowledge.framework)) {
        return {
            content: [
                {
                    type: 'text',
                    text: ti('tools.define_ui_contract.success', {
                        componentCount: String(detectedScreens.length),
                    }),
                },
                {
                    type: 'text',
                    text: generateMobileUIContract(detectedScreens, knowledge),
                },
            ],
        };
    }
    // 5c. Game UI contract — HUD, menus, inventory
    if (isGameProject(knowledge)) {
        return {
            content: [
                {
                    type: 'text',
                    text: ti('tools.define_ui_contract.success', {
                        componentCount: String(detectedScreens.length),
                    }),
                },
                {
                    type: 'text',
                    text: generateGameUIContract(detectedScreens, knowledge),
                },
            ],
        };
    }
    // 5d. Desktop UI contract — window management, menu bar, system tray
    if (isDesktopProject(knowledge)) {
        return {
            content: [
                {
                    type: 'text',
                    text: ti('tools.define_ui_contract.success', {
                        componentCount: String(detectedScreens.length),
                    }),
                },
                {
                    type: 'text',
                    text: generateDesktopUIContract(detectedScreens, knowledge),
                },
            ],
        };
    }
    // 5e. Extension UI contract — popup, options, content overlay
    if (isExtensionProject(knowledge)) {
        return {
            content: [
                {
                    type: 'text',
                    text: ti('tools.define_ui_contract.success', {
                        componentCount: String(detectedScreens.length),
                    }),
                },
                {
                    type: 'text',
                    text: generateExtensionUIContract(detectedScreens, knowledge),
                },
            ],
        };
    }
    // 6. Generate component trees
    const componentTree = generateComponentTree(detectedScreens, specContent, knowledge);
    // 7. Generate data flow
    const dataFlow = generateDataFlow(componentTree, knowledge);
    // 8. Generate loading states
    const loadingStates = generateLoadingStates(componentTree);
    // 9. Generate error states
    const errorStates = generateErrorStates(componentTree);
    const contract = {
        componentTree,
        dataFlow,
        loadingStates,
        errorStates,
    };
    const totalComponents = countComponents(componentTree);
    // 10. SPEC-017a: CSS framework detection + Styling Contract + UX Principles + A11y
    const cssDetection = await detectCSSFramework(knowledge.projectPath);
    const stylingContract = await generateStylingContract(cssDetection);
    const projectContext = determineProjectContext(knowledge.framework, spec.target);
    const uxPrinciples = await generateUXPrinciples(projectContext);
    const componentNames = componentTree.flatMap((n) => [n.name, ...n.children.map((c) => c.name)]);
    const a11yLevel = detectA11yLevel(specContent);
    const a11yContract = generateA11yContract(componentNames, a11yLevel);
    return {
        content: [
            {
                type: 'text',
                text: ti('tools.define_ui_contract.success', { componentCount: String(totalComponents) }),
            },
            {
                type: 'text',
                text: JSON.stringify(contract, null, 2),
            },
            {
                type: 'text',
                text: formatStylingContract(stylingContract),
            },
            {
                type: 'text',
                text: formatUXPrinciples(uxPrinciples),
            },
            {
                type: 'text',
                text: formatA11yContract(a11yContract),
            },
        ],
    };
}
// --- Project context inference ---
function determineProjectContext(framework, target) {
    const fw = (framework ?? '').toLowerCase();
    if (target === 'frontend' || target === 'fullstack') {
        if (fw.includes('next') || fw.includes('nuxt') || fw.includes('remix')) {
            return 'webapp';
        }
        if (fw.includes('react') || fw.includes('vue') || fw.includes('svelte')) {
            return 'webapp';
        }
        return 'web';
    }
    return 'unknown';
}
// --- Screen extraction ---
function extractScreens(content) {
    const screens = [];
    const seen = new Set();
    const patterns = [
        /(?:screen|page|view|route|tab|modal|dialog)\s+["']?(\w[\w\s-]+)["']?/gi,
        /(?:\/[\w-]+)+/g,
    ];
    for (const pattern of patterns) {
        const matches = content.matchAll(pattern);
        for (const match of matches) {
            const screen = match[1] ?? match[0];
            const normalized = screen.trim().replace(/\s+/g, '-');
            if (normalized.length > 2 && !seen.has(normalized.toLowerCase())) {
                seen.add(normalized.toLowerCase());
                screens.push(normalized);
            }
        }
    }
    if (screens.length === 0) {
        screens.push('main');
    }
    return screens.slice(0, 10);
}
// --- Helpers ---
function countComponents(tree) {
    let count = 0;
    for (const node of tree) {
        count += 1;
        count += countComponents(node.children);
    }
    return count;
}
async function readSpecContent(spec) {
    let content = `${spec.title} ${spec.type} ${spec.scope} ${spec.target} ${spec.tags.join(' ')}`;
    try {
        if (spec.specPath) {
            content += ' ' + (await readFile(spec.specPath, 'utf-8'));
        }
    }
    catch {
        /* file not available */
    }
    try {
        if (spec.technicalPath) {
            content += ' ' + (await readFile(spec.technicalPath, 'utf-8'));
        }
    }
    catch {
        /* file not available */
    }
    return content;
}
//# sourceMappingURL=define-ui-contract.js.map