/**
 * BMAD Connector Service
 * Connects Vigthoria VS Extension to the BMAD orchestration system
 * 
 * BMAD = Business Logic Automation + Multi-Agent Deployment + Autonomous Decision Making + Dynamic Resource Allocation
 */

const path = require('path');

class BMADConnector {
    constructor(options = {}) {
        // Vigthoria GoA endpoint (with multi-endpoint fallback)
        this.goaBaseUrls = [
            options.goaEndpoint,
            process.env.VIGTHORIA_AGENT_URL,
            process.env.BMAD_URL,
            'http://10.0.0.2:5005',
            'http://localhost:5005'
        ].filter(Boolean).map((endpoint) => endpoint.replace(/\/$/, ''));

        this.goaBaseUrls = [...new Set(this.goaBaseUrls)];
        this.goaEndpoint = this.goaBaseUrls[0] || 'http://localhost:5005';
        this.bmadApiEndpoint = `${this.goaEndpoint}/api/bmad`;
        this.bmadExecuteEndpoint = `${this.bmadApiEndpoint}/orchestrator/execute`;
        this.bmadStatusEndpoint = `${this.bmadApiEndpoint}/orchestrator/status`;
        this.healthEndpoints = (options.healthEndpoints || this.goaBaseUrls.flatMap((base) => [
            `${base}/health`,
            `${base}/api/health`,
            `${base}/api/bmad/health`
        ])).map((endpoint) => endpoint.replace(/\/$/, ''));
        
        // BMAD system capabilities
        this.capabilities = {
            businessLogicAutomation: true,
            multiAgentDeployment: true,
            autonomousDecisionMaking: true,
            dynamicResourceAllocation: true
        };
        
        // Connection status
        this.connected = false;
        this.lastHealthCheck = null;
        
        // Logger
        this.logger = options.logger || console;
        
        this.logger.info('[BMAD] Connector initialized for Vigthoria GoA at', this.goaEndpoint);
    }
    
    /**
     * Initialize connection to Vigthoria GoA BMAD system
     */
    async initialize() {
        try {
            this.logger.info('[BMAD] Connecting to Vigthoria GoA...');
            
            // Check GoA health
            const health = await this.checkHealth();
            
            if (health.status === 'online') {
                this.connected = true;
                this.logger.info('[BMAD] Connected to Vigthoria GoA successfully');
                this.logger.info('[BMAD] Active agents:', health.agents?.active || 'unknown');
                return { success: true, health };
            } else {
                throw new Error('GoA service not online');
            }
            
        } catch (error) {
            this.logger.error('[BMAD] Failed to connect to Vigthoria GoA:', error.message);
            this.connected = false;
            return { success: false, error: error.message };
        }
    }
    
    /**
     * Check Vigthoria GoA health status
     */
    async checkHealth() {
        for (const endpoint of this.healthEndpoints) {
            try {
                const response = await this.requestJson(endpoint, {}, 5000);

                this.lastHealthCheck = new Date();
                return {
                    status: response?.status === 'healthy' || response?.status === 'online' ? 'online' : (response?.status || 'online'),
                    endpoint,
                    ...response
                };
            } catch (error) {
                this.logger.warn('[BMAD] Health check failed for', endpoint, error.message);
            }
        }

        return {
            status: 'offline',
            error: 'All BMAD health checks failed'
        };
    }
    
    /**
     * Get GoA system status (agents, models, resources)
     */
    async getSystemStatus() {
        try {
            const response = await this.requestJson(this.bmadStatusEndpoint, {}, 5000);
            
            return {
                success: true,
                data: response
            };
            
        } catch (error) {
            this.logger.error('[BMAD] Failed to get system status:', error.message);
            return {
                success: false,
                error: error.message
            };
        }
    }
    
    /**
     * Execute operator mode operation through the live BMAD orchestrator.
     */
    async executeOperation(operationType, params) {
        try {
            if (!this.connected) {
                await this.initialize();
            }
            
            this.logger.info('[BMAD] Executing operation:', operationType);

            const response = await this.requestJson(this.bmadExecuteEndpoint, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(this.buildWorkflowPayload(operationType, params))
            }, 30000);

            const taskId = response?.task_id || response?.workflow_id;
            const task = taskId ? await this.waitForTask(taskId, params) : null;

            return {
                success: true,
                data: response,
                operationType,
                taskId,
                workflowId: response?.bmad_workflow_id || response?.workflow_id || null,
                task
            };
            
        } catch (error) {
            this.logger.error('[BMAD] Operation failed:', error.message);

            return {
                success: false,
                error: error.message,
                operationType
            };
        }
    }
    
    buildWorkflowPayload(operationType, params) {
        const message = params.message || params.prompt || '';
        const workflowProfile = this.getWorkflowProfile(operationType);

        return {
            input_type: 'text',
            content: message,
            analysis_level: workflowProfile.analysisLevel,
            workflow_type: workflowProfile.workflowType,
            context: {
                workspace: {
                    workspacePath: this.resolveWorkspacePath(params.context)
                },
                activeFile: params.context?.activeFile || null,
                history: params.context?.history || []
            }
        };
    }

    getWorkflowProfile(operationType) {
        switch (operationType) {
            case 'deployment':
            case 'configuration':
            case 'database':
            case 'infrastructure':
            case 'automation':
                return {
                    analysisLevel: 'comprehensive',
                    workflowType: 'planning_only'
                };
            case 'monitoring':
            case 'security':
            default:
                return {
                    analysisLevel: 'comprehensive',
                    workflowType: 'full'
                };
        }
    }

    resolveWorkspacePath(context = {}) {
        const workspace = context.workspace || {};
        if (workspace.workspacePath) {
            return workspace.workspacePath;
        }
        if (workspace.workspaceFolder) {
            return workspace.workspaceFolder;
        }
        if (workspace.path) {
            return workspace.path;
        }

        const activeFilePath = context.activeFile?.fullPath;
        if (activeFilePath) {
            return path.dirname(activeFilePath);
        }

        return process.cwd();
    }

    async waitForTask(taskId, params = {}) {
        const timeoutMs = params.timeoutMs || 20000;
        const pollIntervalMs = params.pollIntervalMs || 1500;
        const deadline = Date.now() + timeoutMs;
        let lastStatus = null;

        while (Date.now() < deadline) {
            lastStatus = await this.getTaskStatus(taskId);

            if (!lastStatus) {
                break;
            }

            if (lastStatus.state === 'COMPLETED') {
                const result = await this.getTaskResult(taskId);
                return {
                    completed: true,
                    status: lastStatus,
                    result
                };
            }

            if (lastStatus.state === 'FAILED' || lastStatus.state === 'ERROR') {
                return {
                    completed: false,
                    failed: true,
                    status: lastStatus
                };
            }

            await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
        }

        return {
            completed: false,
            timedOut: true,
            status: lastStatus
        };
    }

    async getTaskStatus(taskId) {
        try {
            return await this.requestJson(`${this.goaEndpoint}/task/${encodeURIComponent(taskId)}/status`, {}, 5000);
        } catch (error) {
            this.logger.warn('[BMAD] Task status fetch failed:', error.message);
            return null;
        }
    }

    async getTaskResult(taskId) {
        try {
            return await this.requestJson(`${this.goaEndpoint}/task/${encodeURIComponent(taskId)}/result`, {}, 5000);
        } catch (error) {
            this.logger.warn('[BMAD] Task result fetch failed:', error.message);
            return null;
        }
    }

    getEndpointVariants(url) {
        const primary = this.goaEndpoint || '';
        if (!primary || !url.startsWith(primary)) {
            return [url];
        }

        const variants = this.goaBaseUrls.map((base) => `${base}${url.slice(primary.length)}`);
        return [...new Set(variants)];
    }

    async requestJson(url, options = {}, timeoutMs = 5000) {
        const urls = this.getEndpointVariants(url);
        let lastError = null;

        for (const candidateUrl of urls) {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

            try {
                const response = await fetch(candidateUrl, {
                    ...options,
                    signal: controller.signal
                });

                if (!response.ok) {
                    throw new Error(`Request failed with status ${response.status}`);
                }

                if (!candidateUrl.startsWith(this.goaEndpoint)) {
                    this.goaEndpoint = candidateUrl.split('/').slice(0, 3).join('/');
                    this.bmadApiEndpoint = `${this.goaEndpoint}/api/bmad`;
                    this.bmadExecuteEndpoint = `${this.bmadApiEndpoint}/orchestrator/execute`;
                    this.bmadStatusEndpoint = `${this.bmadApiEndpoint}/orchestrator/status`;
                }

                return await response.json();
            } catch (error) {
                lastError = error;
            } finally {
                clearTimeout(timeoutId);
            }
        }

        throw lastError || new Error('Request failed across all BMAD endpoints');
    }
    
    /**
     * Deploy agent through BMAD Multi-Agent system
     */
    async deployAgent(agentConfig) {
        return this.executeOperation('deploy_agent', {
            message: `Deploy agent: ${agentConfig.name}`,
            context: {
                agentType: agentConfig.type,
                capabilities: agentConfig.capabilities,
                priority: agentConfig.priority || 'normal'
            }
        });
    }
    
    /**
     * Request autonomous decision from BMAD system
     */
    async autonomousDecision(context) {
        return this.executeOperation('autonomous_decision', {
            message: context.problem || context.task,
            context: {
                constraints: context.constraints,
                objectives: context.objectives,
                resources: context.resources
            }
        });
    }
    
    /**
     * Allocate resources dynamically through BMAD
     */
    async allocateResources(resourceRequirements) {
        return this.executeOperation('allocate_resources', {
            message: `Allocate resources: ${JSON.stringify(resourceRequirements)}`,
            context: resourceRequirements
        });
    }
    
    /**
     * Execute system management task
     */
    async systemManagement(task, params) {
        return this.executeOperation('system_management', {
            message: task,
            context: params
        });
    }
    
    /**
     * Process operator mode message
     * Main entry point for OPERATOR mode
     */
    async processOperatorMessage(message, context = {}) {
        try {
            this.logger.info('[BMAD] Processing operator message');
            
            // Determine operation type from message
            const operationType = context.operatorOperationType || this.detectOperationType(message);
            
            // Execute through BMAD
            const result = await this.executeOperation(operationType, {
                message,
                context,
                timeoutMs: context.bmadTimeoutMs || 20000,
                pollIntervalMs: context.bmadPollIntervalMs || 1500
            });
            
            if (result.success) {
                return {
                    success: true,
                    response: this.formatOperatorResponse(result),
                    operationType,
                    bmadEnabled: true,
                    taskId: result.taskId || null,
                    workflowId: result.workflowId || null,
                    status: result.task?.status || null
                };
            } else {
                throw new Error(result.error);
            }
            
        } catch (error) {
            this.logger.error('[BMAD] Failed to process operator message:', error.message);
            return {
                success: false,
                error: error.message,
                bmadEnabled: false
            };
        }
    }
    
    /**
     * Detect operation type from message content
     */
    detectOperationType(message) {
        const msg = message.toLowerCase();
        
        if (/\b(deploy|release|publish|ship|launch|rollout)\b/.test(msg)) {
            return 'deployment';
        }
        if (/\b(config|configure|setup|settings|environment|env|variables|\.env)\b/.test(msg)) {
            return 'configuration';
        }
        if (/\b(monitor|logs?|metrics|health|status|alerts?)\b/.test(msg)) {
            return 'monitoring';
        }
        if (/\b(security|secure|ssl|tls|certificate|auth|permission|access|firewall)\b/.test(msg)) {
            return 'security';
        }
        if (/\b(database|db|sql|migrate|migration|backup|restore|postgres|mysql|mongo)\b/.test(msg)) {
            return 'database';
        }
        if (/\b(infrastructure|infra|server|docker|kubernetes|k8s|container|nginx|apache|systemd|pm2)\b/.test(msg)) {
            return 'infrastructure';
        }
        if (/\b(automate|automation|script|cron|schedule|pipeline|ci|cd|workflow)\b/.test(msg)) {
            return 'automation';
        }

        return 'general';
    }

    formatOperatorResponse(result) {
        const task = result.task || {};
        const taskResult = task.result || {};
        const taskStatus = task.status || {};
        const output = taskResult.output || taskStatus.partial_output;

        if (output) {
            return this.stringifyOutput(output);
        }

        const lines = [
            'BMAD workflow started successfully.',
            '',
            `Task ID: ${result.taskId || 'unknown'}`,
            `Workflow ID: ${result.workflowId || 'unknown'}`,
            `Stage: ${taskStatus.current_stage || taskStatus.state || 'RUNNING'}`,
            `Progress: ${taskStatus.progress_pct ?? taskStatus.progress ?? 0}%`,
            `Status: ${taskStatus.status_message || result.data?.message || 'Workflow is running in Vigthoria GoA.'}`
        ];

        if (task.timedOut) {
            lines.push('', 'The BMAD workflow is still running on the backend.');
        }

        return lines.join('\n');
    }

    stringifyOutput(output) {
        const text = typeof output === 'string' ? output : JSON.stringify(output, null, 2);
        if (text.length <= 12000) {
            return text;
        }

        return `${text.slice(0, 12000)}\n\n[BMAD output truncated]`;
    }
    
    /**
     * Check if BMAD system is available
     */
    async isAvailable() {
        if (!this.connected) {
            const initResult = await this.initialize();
            return initResult.success;
        }
        return this.connected;
    }
}

module.exports = { BMADConnector };
