"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GenerateComponentsManifestCommand = void 0;
exports.registerGenerateComponentsManifestCommand = registerGenerateComponentsManifestCommand;
const chalk_1 = __importDefault(require("chalk"));
const fs = __importStar(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const fileNames_1 = require("../constants/fileNames");
const spinner_1 = require("../utils/spinner");
const logger_1 = require("../utils/logger");
const hybridAIClient_1 = require("../utils/hybridAIClient");
/**
 * Generate Components Manifest Command
 * Creates typed component list with props, sample data, and required actions
 */
class GenerateComponentsManifestCommand {
    constructor() {
        this.spinner = new spinner_1.EnhancedSpinner("Loading context files...");
        this.aiClient = new hybridAIClient_1.HybridAIClient();
        this.contextDir = ".mycontext";
    }
    async execute(options = {}) {
        this.spinner.start();
        try {
            const context = await this.loadContext();
            if (!context.screensList && !context.features && !context.types) {
                this.spinner.fail("No context files found");
                console.log(chalk_1.default.yellow("\n💡 Generate screens list first:"));
                console.log(chalk_1.default.cyan("   mycontext generate:screens-list\n"));
                return;
            }
            this.spinner.updateText("Analyzing screens and types for components...");
            const prompt = this.buildComponentsPrompt(context);
            this.spinner.updateText("Generating components manifest with AI...");
            const response = await this.aiClient.generateText(prompt, {
                maxTokens: 8192,
                temperature: 0.3,
            });
            if (!response) {
                throw new Error("AI generation failed");
            }
            const components = this.parseComponentsResponse(response.text);
            const markdown = this.generateMarkdown(components);
            const outputPath = options.output || path_1.default.join(this.contextDir, "03-components.md");
            await fs.ensureDir(path_1.default.dirname(outputPath));
            await fs.writeFile(outputPath, markdown, "utf-8");
            // Also generate JSON for programmatic use
            const jsonPath = path_1.default.join(this.contextDir, "03-components.json");
            await fs.writeFile(jsonPath, JSON.stringify(components, null, 2), "utf-8");
            this.spinner.updateText("Syncing with Living Brain...");
            await this.syncWithLivingContext(components);
            this.spinner.succeed("Components manifest generated!");
            console.log(chalk_1.default.green(`\n✅ Generated ${components.length} component definitions`));
            console.log(chalk_1.default.gray(`   Markdown: ${outputPath}`));
            console.log(chalk_1.default.gray(`   JSON: ${jsonPath}\n`));
            // Print summary by type
            const byType = this.groupByType(components);
            console.log(chalk_1.default.bold("🧩 Components by Type:"));
            Object.entries(byType).forEach(([type, comps]) => {
                console.log(chalk_1.default.cyan(`   ${type}: ${comps.length}`));
            });
            console.log(chalk_1.default.yellow("\n💡 Next Steps:"));
            console.log(chalk_1.default.gray("   1. mycontext generate actions"));
            console.log(chalk_1.default.gray("   2. mycontext generate-components"));
        }
        catch (error) {
            this.spinner.fail(`Failed to generate components manifest: ${error.message}`);
            logger_1.logger.error("Components manifest generation error:", error);
        }
    }
    async loadContext() {
        const context = {};
        const dir = this.contextDir;
        const files = [
            { key: "screensList", path: "02-screens-list.md" },
            { key: "features", path: "01a-features.md" },
            { key: "userFlows", path: "01b-user-flows.md" },
            { key: "types", path: "02-types.ts" },
            { key: "prd", path: fileNames_1.CONTEXT_FILES.PRD },
            { key: "screenshotContext", path: "context.md" },
        ];
        for (const file of files) {
            const filePath = path_1.default.join(dir, file.path);
            if (await fs.pathExists(filePath)) {
                context[file.key] = await fs.readFile(filePath, "utf-8");
            }
        }
        return context;
    }
    buildComponentsPrompt(context) {
        let prompt = `You are a React component architect. Analyze the project context and define UI components.
    
OUTPUT ONLY A JSON ARRAY. NO MARKDOWN BLOCKS. NO EXPLANATION.

For each component:
- name: PascalCase
- type: layout|display|interactive|form|navigation
- description: Clear purpose
- props: Array of { name, type, required (boolean), description }
- actions: Array of callback names
- usedInScreens: Array of screen names

Output format:
[
  {
    "name": "TaskCard",
    "type": "display",
    "description": "Displays a task",
    "props": [{"name": "task", "type": "Task", "required": true, "description": "Task data"}],
    "actions": ["onComplete"],
    "usedInScreens": ["DashboardScreen"]
  }
]

PROJECT CONTEXT:
`;
        if (context.screensList) {
            prompt += `\n## Screens List:\n${context.screensList.substring(0, 3000)}\n`;
        }
        if (context.features) {
            prompt += `\n## Features:\n${context.features.substring(0, 2000)}\n`;
        }
        prompt += `
Identify core components for layout, navigation, and main feature interactions. Be comprehensive but concise.`;
        return prompt;
    }
    parseComponentsResponse(response) {
        try {
            // Find the first '[' and last ']' to extract the JSON array safely
            const startIndex = response.indexOf("[");
            const endIndex = response.lastIndexOf("]");
            if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
                logger_1.logger.warn("Could not find valid JSON array markers in response");
                return [];
            }
            const jsonStr = response.substring(startIndex, endIndex + 1);
            // Basic sanity check for common truncation/malformation
            const sanitizedJson = jsonStr;
            if (!sanitizedJson.endsWith("]")) {
                // Attempt to close open braces/brackets if clearly truncated
                logger_1.logger.warn("JSON seems truncated, attempting basic repair...");
                // This is a very basic repair, better to handle in AI prompt/tokens but helpful for robustness
            }
            const components = JSON.parse(sanitizedJson);
            return components.map((c) => ({
                name: c.name || "UnnamedComponent",
                type: c.type || "display",
                description: c.description || "",
                props: (c.props || []).map((p) => ({
                    name: p.name,
                    type: p.type || "any",
                    required: p.required ?? true,
                    description: p.description || "",
                    sampleValue: p.sampleValue,
                })),
                sampleData: c.sampleData || {},
                actions: c.actions || [],
                usedInScreens: c.usedInScreens || [],
            }));
        }
        catch (error) {
            logger_1.logger.error("Failed to parse components response:", error);
            // If parsing failed due to truncation, we should return whatever we can parse or a clean error
            return [];
        }
    }
    async asyncLoadLivingContext() {
        const contextPath = path_1.default.join(this.contextDir, "context.json");
        if (await fs.pathExists(contextPath)) {
            return await fs.readJson(contextPath);
        }
        return null;
    }
    async syncWithLivingContext(components) {
        try {
            const livingContext = await this.asyncLoadLivingContext();
            if (!livingContext)
                return;
            // Map to Component type used in LivingContext
            // Note: LivingContext.components expects objects with status
            const mappedComponents = components.map(comp => ({
                name: comp.name,
                description: comp.description,
                type: (["form", "display", "layout", "interactive"].includes(comp.type)
                    ? comp.type
                    : "display"),
                status: "planned",
                priority: "medium",
                dependencies: [],
                tags: [],
                usedInScreens: comp.usedInScreens,
                props: comp.props,
                sampleData: comp.sampleData,
                actions: comp.actions
            }));
            // Update or merge components
            // For now, we'll replace the components list with the generated one
            livingContext.components = mappedComponents;
            livingContext.metadata.lastUpdatedAt = new Date().toISOString();
            const contextPath = path_1.default.join(this.contextDir, "context.json");
            await fs.writeJson(contextPath, livingContext, { spaces: 2 });
            logger_1.logger.info(`Synced ${components.length} components to context.json`);
        }
        catch (error) {
            logger_1.logger.error("Failed to sync components with living context:", error);
        }
    }
    groupByType(components) {
        return components.reduce((acc, comp) => {
            const type = comp.type || "other";
            if (!acc[type])
                acc[type] = [];
            acc[type].push(comp);
            return acc;
        }, {});
    }
    generateMarkdown(components) {
        let md = `> [!IMPORTANT]
> **READ-ONLY VIEW**: This file is an export from \`context.json\`. 
> Do NOT edit this file directly. Any manual changes will be overwritten.
> **Source of Truth**: [\`.mycontext/context.json\`](file://./.mycontext/context.json)
> **Consolidated View**: For the full architecture, see [\`04-component-list.md\`](file://./.mycontext/04-component-list.md)

# Components Manifest

> Auto-generated component specifications with props and sample data.
> Total: ${components.length} components

## Overview

| Component | Type | Props | Actions | Used In |
|-----------|------|-------|---------|---------|
`;
        components.forEach(comp => {
            md += `| ${comp.name} | ${comp.type} | ${comp.props.length} | ${comp.actions.length} | ${comp.usedInScreens.length} screens |\n`;
        });
        md += `\n---\n\n## Component Specifications\n\n`;
        const byType = this.groupByType(components);
        for (const [type, comps] of Object.entries(byType)) {
            md += `### ${type.charAt(0).toUpperCase() + type.slice(1)} Components\n\n`;
            for (const comp of comps) {
                md += `#### ${comp.name}\n\n`;
                md += `**Description**: ${comp.description}\n\n`;
                md += `**Used in**: ${comp.usedInScreens.join(", ") || "N/A"}\n\n`;
                md += `**Props**:\n\`\`\`typescript\ninterface ${comp.name}Props {\n`;
                comp.props.forEach(prop => {
                    md += `  ${prop.name}${prop.required ? "" : "?"}: ${prop.type}; // ${prop.description}\n`;
                });
                md += `}\n\`\`\`\n\n`;
                if (Object.keys(comp.sampleData).length > 0) {
                    md += `**Sample Data**:\n\`\`\`json\n${JSON.stringify(comp.sampleData, null, 2)}\n\`\`\`\n\n`;
                }
                if (comp.actions.length > 0) {
                    md += `**Actions Required**: ${comp.actions.map(a => `\`${a}\``).join(", ")}\n\n`;
                }
                md += `---\n\n`;
            }
        }
        md += `\n---
*Generated by MyContext CLI*
*Last updated: ${new Date().toISOString()}*
`;
        return md;
    }
}
exports.GenerateComponentsManifestCommand = GenerateComponentsManifestCommand;
function registerGenerateComponentsManifestCommand(program) {
    program
        .command("generate:components-manifest")
        .alias("gcm")
        .description("Generate component specifications with props, sample data, and actions")
        .option("-o, --output <path>", "Output file path", ".mycontext/03-components.md")
        .option("-v, --verbose", "Enable verbose logging")
        .option("--include-demo", "Include demo/sample data for each component")
        .action(async (options) => {
        const command = new GenerateComponentsManifestCommand();
        await command.execute(options);
    });
}
//# sourceMappingURL=generate-components-manifest.js.map