"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.BrainClient = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const core_1 = require("@myycontext/core");
const uuid_1 = require("uuid");
const chalk_1 = __importDefault(require("chalk"));
class BrainClient {
    constructor(workingDirectory) {
        this.brainPath = path.join(workingDirectory, '.mycontext', 'context.json');
    }
    static getInstance(workingDirectory = process.cwd()) {
        if (!BrainClient.instance) {
            BrainClient.instance = new BrainClient(workingDirectory);
        }
        // Update path if working directory changes (edge case handling)
        if (path.dirname(path.dirname(BrainClient.instance.brainPath)) !== workingDirectory) {
            BrainClient.instance.brainPath = path.join(workingDirectory, '.mycontext', 'context.json');
        }
        return BrainClient.instance;
    }
    async getBrain() {
        try {
            if (await fs.pathExists(this.brainPath)) {
                const context = await fs.readJson(this.brainPath);
                if (context.brain)
                    return context.brain;
            }
            return JSON.parse(JSON.stringify(core_1.INITIAL_BRAIN_STATE));
        }
        catch (error) {
            console.error(chalk_1.default.red('Failed to read context/brain:'), error);
            return JSON.parse(JSON.stringify(core_1.INITIAL_BRAIN_STATE));
        }
    }
    incrementVersion(version) {
        const parts = version.split('.').map(Number);
        if (parts.length !== 3 || parts.some(isNaN) || parts[2] === undefined)
            return version; // Fallback
        parts[2]++; // Increment patch
        return parts.join('.');
    }
    async saveBrain(brain) {
        try {
            // Auto-increment version on save for alignment
            const currentVersion = brain.version || "1.0.0";
            brain.version = this.incrementVersion(currentVersion);
            let context = {};
            if (await fs.pathExists(this.brainPath)) {
                context = await fs.readJson(this.brainPath);
            }
            context.brain = brain;
            await fs.ensureDir(path.dirname(this.brainPath));
            await fs.writeJson(this.brainPath, context, { spaces: 2 });
        }
        catch (error) {
            console.error(chalk_1.default.red('Failed to save brain to context:'), error);
        }
    }
    async addUpdate(agentName, role, type, message, metadata) {
        const brain = await this.getBrain();
        const update = {
            id: (0, uuid_1.v4)(),
            timestamp: Date.now(),
            agent: agentName,
            role,
            type,
            message,
            metadata
        };
        brain.updates.push(update);
        // Log to console for CLI visibility
        const color = type === 'error' ? chalk_1.default.red : type === 'action' ? chalk_1.default.green : chalk_1.default.gray;
        const icon = type === 'error' ? '❌' : type === 'action' ? '⚡' : type === 'thought' ? '💭' : '✅';
        console.log(color(`[${agentName}] ${icon} ${message}`));
        await this.saveBrain(brain);
    }
    async updateArtifact(type, content, filePath) {
        const brain = await this.getBrain();
        if (!brain.artifacts)
            brain.artifacts = {};
        if (!brain.artifacts[type]) {
            brain.artifacts[type] = {
                path: filePath,
                content,
                version: 1,
                lastUpdated: Date.now()
            };
        }
        else {
            brain.artifacts[type].content = content;
            brain.artifacts[type].version++;
            brain.artifacts[type].lastUpdated = Date.now();
        }
        await this.saveBrain(brain);
    }
    async setNarrative(narrative) {
        const brain = await this.getBrain();
        brain.narrative = narrative;
        await this.saveBrain(brain);
    }
    async setStatus(status) {
        const brain = await this.getBrain();
        brain.status = status;
        await this.saveBrain(brain);
    }
    async registerComponent(name, description, path, dependencies) {
        const brain = await this.getBrain();
        if (!brain.registry)
            brain.registry = { components: [] };
        // Check if component already exists
        const index = brain.registry.components.findIndex((c) => c.path === path);
        const newComp = { name, description, path, dependencies };
        if (index !== -1) {
            brain.registry.components[index] = newComp;
        }
        else {
            brain.registry.components.push(newComp);
        }
        await this.saveBrain(brain);
    }
    async getRegistry() {
        const brain = await this.getBrain();
        return brain.registry || { components: [] };
    }
    async reset() {
        // Deep copy to avoid mutating the imported constant
        const freshBrain = JSON.parse(JSON.stringify(core_1.INITIAL_BRAIN_STATE));
        await this.saveBrain(freshBrain);
    }
    /**
     * Record token usage for a single LLM call.
     * Updates both the per-call metadata in the latest BrainUpdate (if any)
     * and the cumulative usage summary on brain.usage.
     */
    async recordTokenUsage(agentName, provider, model, tokens, costUSD) {
        const brain = await this.getBrain();
        if (!brain.usage) {
            brain.usage = {
                totalInputTokens: 0,
                totalOutputTokens: 0,
                totalTokens: 0,
                totalCostUSD: 0,
                callCount: 0,
                byAgent: {},
                byProvider: {},
            };
        }
        const u = brain.usage;
        u.totalInputTokens += tokens.inputTokens;
        u.totalOutputTokens += tokens.outputTokens;
        u.totalTokens += tokens.totalTokens;
        u.totalCostUSD += costUSD;
        u.callCount += 1;
        // Per-agent accumulation
        if (!u.byAgent[agentName]) {
            u.byAgent[agentName] = { calls: 0, inputTokens: 0, outputTokens: 0, costUSD: 0 };
        }
        const ag = u.byAgent[agentName];
        ag.calls += 1;
        ag.inputTokens += tokens.inputTokens;
        ag.outputTokens += tokens.outputTokens;
        ag.costUSD += costUSD;
        // Per-provider accumulation
        if (!u.byProvider[provider]) {
            u.byProvider[provider] = { calls: 0, inputTokens: 0, outputTokens: 0, costUSD: 0 };
        }
        const pr = u.byProvider[provider];
        pr.calls += 1;
        pr.inputTokens += tokens.inputTokens;
        pr.outputTokens += tokens.outputTokens;
        pr.costUSD += costUSD;
        await this.saveBrain(brain);
    }
    /** Return the cumulative token usage summary for the current context */
    async getUsageSummary() {
        const brain = await this.getBrain();
        return brain.usage;
    }
}
exports.BrainClient = BrainClient;
//# sourceMappingURL=BrainClient.js.map