"use strict";
/**
 * Sub-Agent Orchestrator
 *
 * Manages the registration, execution, and orchestration of sub-agents.
 * Supports both sequential and parallel execution patterns.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.orchestrator = exports.SubAgentOrchestrator = void 0;
const subAgentPersonalities_1 = require("../../constants/subAgentPersonalities");
const spinner_1 = require("../../utils/spinner");
const logger_1 = require("../../utils/logger");
const chalk_1 = __importDefault(require("chalk"));
class SimpleSemaphore {
    constructor(maxConcurrency) {
        this.maxConcurrency = maxConcurrency;
        this.active = 0;
        this.queue = [];
    }
    async acquire() {
        if (this.active < this.maxConcurrency) {
            this.active++;
            return;
        }
        return new Promise((resolve) => {
            this.queue.push(resolve);
        });
    }
    release() {
        this.active--;
        if (this.queue.length > 0) {
            this.active++;
            const next = this.queue.shift();
            if (next)
                next();
        }
    }
    async run(fn) {
        await this.acquire();
        try {
            return await fn();
        }
        finally {
            this.release();
        }
    }
}
class SubAgentOrchestrator {
    constructor() {
        this.semaphore = new SimpleSemaphore(5);
        this.agents = new Map();
        this.executionHistory = [];
        this.activeWorkflows = new Set();
        this.totalExecutions = 0;
        this.totalExecutionTime = 0;
    }
    /**
     * Register a sub-agent with the orchestrator
     */
    registerAgent(agent) {
        if (this.agents.has(agent.name)) {
            logger_1.logger.warn(`Sub-agent '${agent.name}' is already registered. Overwriting.`);
        }
        this.agents.set(agent.name, agent);
        logger_1.logger.verbose(`Registered sub-agent: ${agent.name}`);
    }
    /**
     * Execute a single sub-agent
     */
    async executeAgent(agentName, input) {
        return this.semaphore.run(async () => {
            const agent = this.agents.get(agentName);
            if (!agent) {
                throw new Error(`Sub-agent '${agentName}' not found. Available agents: ${Array.from(this.agents.keys()).join(", ")}`);
            }
            const personality = (0, subAgentPersonalities_1.getSubAgentPersonality)(agentName);
            const spinner = new spinner_1.EnhancedSpinner(`🤖 Executing ${agentName}...`);
            try {
                spinner.start();
                // Validate input if the agent supports it
                if (agent.validate) {
                    const isValid = await agent.validate(input);
                    if (!isValid) {
                        throw new Error(`Input validation failed for sub-agent '${agentName}'`);
                    }
                }
                const startTime = Date.now();
                const result = await agent.run(input);
                const executionTime = Date.now() - startTime;
                // Record execution
                this.recordExecution(agentName, true, executionTime, result);
                spinner.success({ text: `${agentName} completed in ${executionTime}ms` });
                if (personality) {
                    console.log(chalk_1.default.blue(`💡 ${personality.description}`));
                }
                return result;
            }
            catch (error) {
                const executionTime = 0;
                this.recordExecution(agentName, false, executionTime, undefined, error);
                spinner.error({ text: `${agentName} failed: ${error}` });
                throw error;
            }
            finally {
                // Cleanup if the agent supports it
                if (agent.cleanup) {
                    try {
                        await agent.cleanup();
                    }
                    catch (cleanupError) {
                        console.warn(chalk_1.default.yellow(`⚠️  Cleanup failed for ${agentName}: ${cleanupError}`));
                    }
                }
            }
        });
    }
    /**
     * Execute a workflow with multiple sub-agents
     */
    async executeWorkflow(workflow) {
        const workflowId = `workflow-${Date.now()}`;
        this.activeWorkflows.add(workflowId);
        const spinner = new spinner_1.EnhancedSpinner(`🔄 Executing workflow with ${workflow.length} steps...`);
        const startTime = Date.now();
        const results = [];
        try {
            spinner.start();
            // Build dependency graph
            const dependencyGraph = this.buildDependencyGraph(workflow);
            // Execute steps in dependency order
            const executedSteps = new Set();
            const stepResults = new Map();
            while (executedSteps.size < workflow.length) {
                const readySteps = this.getReadySteps(workflow, dependencyGraph, executedSteps, stepResults);
                if (readySteps.length === 0) {
                    throw new Error("Circular dependency detected in workflow");
                }
                // Execute ready steps in parallel
                const parallelResults = await Promise.allSettled(readySteps.map(async (step) => {
                    const stepStartTime = Date.now();
                    try {
                        // Resolve input dependencies
                        const resolvedInput = this.resolveStepInput(step, stepResults);
                        const result = await this.executeAgent(step.agentName, resolvedInput);
                        const stepExecutionTime = Date.now() - stepStartTime;
                        const stepResult = {
                            stepId: step.id,
                            agentName: step.agentName,
                            success: true,
                            data: result,
                            executionTime: stepExecutionTime,
                            startTime: new Date(stepStartTime),
                            endTime: new Date(),
                        };
                        results.push(stepResult);
                        stepResults.set(step.id, result);
                        executedSteps.add(step.id);
                        return stepResult;
                    }
                    catch (error) {
                        const stepExecutionTime = Date.now() - stepStartTime;
                        const stepResult = {
                            stepId: step.id,
                            agentName: step.agentName,
                            success: false,
                            error: error,
                            executionTime: stepExecutionTime,
                            startTime: new Date(stepStartTime),
                            endTime: new Date(),
                        };
                        results.push(stepResult);
                        throw error;
                    }
                }));
                // Check for failures
                const failures = parallelResults.filter((result) => result.status === "rejected");
                if (failures.length > 0) {
                    const errorMessages = failures
                        .map((f) => f.reason)
                        .join(", ");
                    throw new Error(`Workflow step failures: ${errorMessages}`);
                }
            }
            const executionTime = Date.now() - startTime;
            const success = results.every((r) => r.success);
            spinner.success({ text: `Workflow completed in ${executionTime}ms` });
            return {
                success,
                data: stepResults.get(workflow[workflow.length - 1]?.id || ""),
                executionTime,
                steps: results,
            };
        }
        catch (error) {
            const executionTime = Date.now() - startTime;
            spinner.error({ text: `Workflow failed: ${error}` });
            return {
                success: false,
                error: error,
                executionTime,
                steps: results,
            };
        }
        finally {
            this.activeWorkflows.delete(workflowId);
        }
    }
    /**
     * Execute multiple sub-agents in parallel
     */
    async executeParallel(agents) {
        const spinner = new spinner_1.EnhancedSpinner(`🔄 Executing ${agents.length} agents in parallel...`);
        try {
            spinner.start();
            const results = await Promise.allSettled(agents.map(async ({ name, input }) => {
                const result = await this.executeAgent(name, input);
                return { name, result };
            }));
            const resultMap = new Map();
            const failures = [];
            results.forEach((result, index) => {
                if (result.status === "fulfilled") {
                    resultMap.set(result.value.name, result.value.result);
                }
                else {
                    failures.push(`${agents[index]?.name || "Unknown"}: ${result.reason}`);
                }
            });
            if (failures.length > 0) {
                spinner.warn({ text: `Some agents failed: ${failures.join(", ")}` });
            }
            else {
                spinner.success({
                    text: `All ${agents.length} agents completed successfully`,
                });
            }
            return resultMap;
        }
        catch (error) {
            spinner.error({ text: `Parallel execution failed: ${error}` });
            throw error;
        }
    }
    /**
     * Get orchestration status
     */
    async getStatus() {
        const agentStatuses = await Promise.all(Array.from(this.agents.values()).map(async (agent) => {
            if (agent.getStatus) {
                return await agent.getStatus();
            }
            return {
                name: agent.name,
                status: "idle",
                errorCount: 0,
                successCount: 0,
            };
        }));
        const successfulExecutions = this.executionHistory.filter((r) => r.success).length;
        const totalExecutions = this.executionHistory.length;
        const errorRate = totalExecutions > 0
            ? (totalExecutions - successfulExecutions) / totalExecutions
            : 0;
        return {
            activeWorkflows: this.activeWorkflows.size,
            registeredAgents: Array.from(this.agents.keys()),
            totalExecutions: this.totalExecutions,
            averageExecutionTime: this.totalExecutions > 0
                ? this.totalExecutionTime / this.totalExecutions
                : 0,
            errorRate,
        };
    }
    /**
     * Get a registered sub-agent
     */
    getAgent(name) {
        return this.agents.get(name);
    }
    /**
     * List all registered sub-agents
     */
    listAgents() {
        return Array.from(this.agents.keys());
    }
    /**
     * Remove a sub-agent
     */
    removeAgent(name) {
        return this.agents.delete(name);
    }
    /**
     * Clear all sub-agents
     */
    clearAgents() {
        this.agents.clear();
    }
    // Private helper methods
    recordExecution(agentName, success, executionTime, data, error) {
        this.totalExecutions++;
        this.totalExecutionTime += executionTime;
        const stepResult = {
            stepId: `single-${Date.now()}`,
            agentName,
            success,
            data,
            error,
            executionTime,
            startTime: new Date(Date.now() - executionTime),
            endTime: new Date(),
        };
        this.executionHistory.push(stepResult);
    }
    buildDependencyGraph(workflow) {
        const graph = new Map();
        workflow.forEach((step) => {
            graph.set(step.id, step.dependencies || []);
        });
        return graph;
    }
    getReadySteps(workflow, dependencyGraph, executedSteps, stepResults) {
        return workflow.filter((step) => {
            if (executedSteps.has(step.id)) {
                return false;
            }
            const dependencies = dependencyGraph.get(step.id) || [];
            return dependencies.every((dep) => executedSteps.has(dep));
        });
    }
    resolveStepInput(step, stepResults) {
        if (typeof step.input === "function") {
            return step.input(stepResults);
        }
        return step.input;
    }
}
exports.SubAgentOrchestrator = SubAgentOrchestrator;
// Export a singleton instance
exports.orchestrator = new SubAgentOrchestrator();
//# sourceMappingURL=SubAgentOrchestrator.js.map