"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.ContextEnrichmentService = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const child_process_1 = require("child_process");
const AICore_1 = require("../core/ai/AICore");
const contextRenderer_1 = require("../utils/contextRenderer");
const contextExportsImporter_1 = require("../utils/contextExportsImporter");
/**
 * ContextEnrichmentService
 *
 * Logic for high-fidelity "Living Brain" generation and
 * automated background enrichment.
 */
class ContextEnrichmentService {
    constructor(projectRoot = process.cwd()) {
        this.gapThreshold = 75; // Trigger enrichment if progress < 75%
        this.projectRoot = projectRoot;
    }
    /**
     * Main entry point for enrichment (Synchronous)
     */
    async enrich(options = {}) {
        const aiCore = this.getAICore();
        const contextDir = path.join(this.projectRoot, ".mycontext");
        const jsonPath = path.join(contextDir, "context.json");
        const lockPath = path.join(contextDir, ".enrichment.lock");
        // 1. Check lock
        if (await fs.pathExists(lockPath)) {
            if (!options.internal) {
                console.log(chalk_1.default.yellow("⚠️  Brain enrichment already in progress (lock file found)."));
            }
            return null;
        }
        try {
            if (options.internal) {
                await fs.ensureDir(contextDir);
                await fs.writeFile(lockPath, JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }));
            }
            if (options.spinner)
                options.spinner.updateText("🚀 Generating Living Brain (JSON Context)...");
            // Load existing
            let existingContext = null;
            try {
                if (await fs.pathExists(jsonPath)) {
                    existingContext = await fs.readJson(jsonPath);
                }
            }
            catch (e) { /* ignore */ }
            // Import manual edits if requested
            if (existingContext && options.full) {
                try {
                    existingContext = await (0, contextExportsImporter_1.importContextExports)(contextDir, existingContext);
                }
                catch { /* ignore */ }
            }
            const prompt = this.buildEnrichmentPrompt(existingContext, options.projectContext);
            const schema = this.getLivingContextSchema();
            const livingContextData = await aiCore.generateStructuredText(prompt, schema, {
                model: options.model
            });
            const livingContext = this.assembleLivingContext(livingContextData, existingContext);
            // Save
            await fs.ensureDir(contextDir);
            await fs.writeJson(jsonPath, livingContext, { spaces: 2 });
            // Export views
            if (options.spinner)
                options.spinner.updateText("📝 Exporting Markdown views...");
            await this.exportMarkdownViews(contextDir, livingContext);
            if (options.spinner)
                options.spinner.success({ text: "🎉 Living Context generated and exported!" });
            return livingContext;
        }
        finally {
            if (options.internal && await fs.pathExists(lockPath)) {
                await fs.remove(lockPath);
            }
        }
    }
    /**
     * Spawns a detached background process to perform enrichment
     */
    async triggerBackgroundEnrichment() {
        const contextDir = path.join(this.projectRoot, ".mycontext");
        const lockPath = path.join(contextDir, ".enrichment.lock");
        if (await fs.pathExists(lockPath))
            return;
        // Detect entry point (dist/cli.js or src/cli.ts)
        const cliPath = path.join(__dirname, "..", "cli.js");
        const entryPath = fs.existsSync(cliPath) ? cliPath : process.argv[1];
        if (!entryPath)
            return;
        // We use 'generate context --full --internal-enrich'
        // Passing --project to ensure it targets the right directory
        const args = [entryPath, "generate", "context", "--full", "--internal-enrich", "--project", this.projectRoot];
        const child = (0, child_process_1.spawn)(process.execPath, args, {
            cwd: this.projectRoot,
            detached: true,
            stdio: "ignore",
        });
        child.unref();
        console.log(chalk_1.default.gray("   • Backgrounding brain enrichment (self-correction in progress)..."));
    }
    /**
     * Checks if enrichment is needed based on the current context state
     */
    async needsEnrichment(context) {
        const memory = context.brain?.memory?.lastSync;
        if (memory?.overallProgress !== undefined && memory.overallProgress < this.gapThreshold) {
            return true;
        }
        // Explicit gaps check
        const gaps = context.brain?.memory?.lastSync?.context_gaps;
        if (gaps && gaps.length > 0)
            return true;
        if (!context.project?.description || context.project.description.length < 50)
            return true;
        return false;
    }
    buildEnrichmentPrompt(existing, update) {
        const desc = update?.description || "No description provided.";
        if (existing && existing.prd && Object.keys(existing.prd).length > 0) {
            return `
Update and refine the following project context based on the provided description/update.
EXISTING CONTEXT:
${JSON.stringify(existing).slice(0, 15000)}

PROJECT DESCRIPTION / UPDATE:
${desc}

INSTRUCTIONS:
1. Merge the new information from the description into the existing context.
2. Update technical specs if the description mentions specific tech stacks (e.g. Next.js, Tailwind).
3. valid existing details should be preserved unless contradicted by the new description.
`;
        }
        return `
Generate a comprehensive project context based on the provided project analysis/description.

PROJECT ANALYSIS:
${desc}

INSTRUCTIONS:
1. Analyze the project details provided above (which may include file structure, tech stack, and README summary).
2. Extract functional requirements, user flows, and technical limits.
3. If the description includes a file tree, infer the project architecture from it.
4. Identify all necessary UI components and group them logically (e.g. Auth, Sidebar, Dashboard).
5. Generate a complete PRD, Technical Spec, and Component Architecture that reflects this ACTUAL existing project.
`;
    }
    getLivingContextSchema() {
        return `
{
  "prd": { "title": "...", "problemStatement": "...", "goals": [], "targetAudience": "...", "successMetrics": [] },
  "features": [{ "id": "...", "name": "...", "description": "...", "priority": "high|medium|low", "userValue": "...", "acceptanceCriteria": [], "dependencies": [] }],
  "flows": [{ "id": "...", "name": "...", "description": "...", "steps": [], "actors": [] }],
  "edgeCases": [{ "id": "...", "category": "...", "description": "...", "mitigation": "..." }],
  "brand": {
    "theme": "light|dark",
    "colors": { "primary": "#...", "background": "#...", "text": "#...", "accent": "#..." },
    "typography": { "fontFamily": "...", "headingScale": "..." },
    "designPrinciples": []
  },
  "types": {
    "entities": [{ "name": "...", "description": "...", "schema": "export interface ... { ... }" }],
    "shared": [{ "name": "...", "description": "...", "schema": "export interface ... { ... }" }]
  },
  "specs": {
    "architecture": "...",
    "techStack": { "frontend": [], "backend": [], "database": [], "other": [] },
    "apiEndpoints": [{ "path": "...", "method": "...", "description": "...", "authRequired": true }],
    "databaseSchema": { "tables": [{ "name": "...", "columns": [{ "name": "...", "type": "...", "constraints": [] }] }] }
  },
  "components": [
    {
       "name": "ComponentName",
       "description": "...",
       "type": "form|layout|display|interactive",
       "group": "Auth|Dashboard|etc",
       "status": "planned"
    }
  ]
}
`;
    }
    assembleLivingContext(data, existing) {
        const existingDesc = existing?.metadata?.projectConfig?.description ||
            existing?.project?.description ||
            existing?.prd?.problemStatement || "";
        const isGrounded = existingDesc.includes("GROUNDING DOC");
        return {
            ...data,
            prd: {
                ...data.prd,
                problemStatement: isGrounded ? existingDesc : (data.prd?.problemStatement || "")
            },
            metadata: {
                version: "1.0.0",
                generatedAt: new Date().toISOString(),
                lastUpdatedAt: new Date().toISOString(),
                projectConfig: {
                    id: existing?.metadata?.projectConfig?.id || require("crypto").randomUUID(),
                    name: data.prd.title,
                    description: isGrounded ? existingDesc : data.prd.problemStatement,
                    createdAt: existing?.metadata?.projectConfig?.createdAt || new Date().toISOString(),
                    updatedAt: new Date().toISOString(),
                    contextPath: ".mycontext",
                    version: "0.1.0",
                    status: "context-generated"
                }
            },
            components: Array.isArray(data.components) ? data.components.map((c) => ({
                ...c,
                status: c.status || "planned"
            })) : (existing?.components || []),
            actions: Array.isArray(data.actions) ? data.actions : (existing?.actions || []),
            routes: Array.isArray(data.routes) ? data.routes : (existing?.routes || [])
        };
    }
    async exportMarkdownViews(contextDir, context) {
        const renders = [
            { name: "01-prd.md", content: contextRenderer_1.ContextRenderer.renderPRD(context) },
            { name: "02-technical-specs.md", content: contextRenderer_1.ContextRenderer.renderTechnicalSpecs(context) },
            { name: "03-brand-guide.md", content: contextRenderer_1.ContextRenderer.renderBrandGuide(context) },
            { name: "04-user-flows.md", content: contextRenderer_1.ContextRenderer.renderUserFlows(context) },
        ];
        for (const render of renders) {
            await fs.writeFile(path.join(contextDir, render.name), render.content);
        }
    }
    getAICore() {
        let aiCore;
        try {
            aiCore = AICore_1.AICore.getInstance();
        }
        catch {
            aiCore = AICore_1.AICore.getInstance({
                fallbackEnabled: true,
                workingDirectory: this.projectRoot,
            });
        }
        // Ensure providers are refreshed to pick up latest env vars
        aiCore.forceRefresh();
        return aiCore;
    }
}
exports.ContextEnrichmentService = ContextEnrichmentService;
//# sourceMappingURL=ContextEnrichmentService.js.map