// Vigthoria AI Service
// Extracted from monolithic extension.js for proper modularity

const { CONFIG, AI_MODES } = require('../utils/config');
const { BMADConnector } = require('./bmad-connector');

const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
    const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS || '3900000';
    const parsed = Number.parseInt(rawValue, 10);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : 3900000;
})();

const DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS = (() => {
    const rawValue = process.env.VIGTHORIA_AGENT_IDLE_TIMEOUT_MS || process.env.V3_AGENT_IDLE_TIMEOUT_MS || '90000';
    const parsed = Number.parseInt(rawValue, 10);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : 90000;
})();

class AIService {
    constructor() {
        this.ideUrl = CONFIG.server.ideUrl;
        this.ideFallbackUrl = CONFIG.server.ideFallbackUrl;
        // Model Router API URL
        this.apiUrl = CONFIG.server.modelRouterUrl || 'https://coder.vigthoria.io/api/model-router';
        this.apiFallbackUrl = CONFIG.server.modelRouterFallbackUrl || 'http://localhost:4009';
        this.healthPaths = CONFIG.server.healthPaths || ['/health', '/api/health', '/'];
        this.isConnected = false;
        this.requestQueue = [];
        this.processing = false;
        this.multiAIOrchestrator = null;
        this.secureTokenManager = null;
        this.bmadConnector = new BMADConnector({
            goaEndpoint: CONFIG.server.services.agents || process.env.VIGTHORIA_AGENT_URL || 'http://localhost:5005',
            logger: console
        });
        
        console.log('[AI-SERVICE] 🔧 Initialized with API URL:', this.apiUrl);
    }

    // Methods called by vigthoria-webview-provider.js setServices()
    setMultiAIOrchestrator(orchestrator) {
        this.multiAIOrchestrator = orchestrator;
        console.log('✅ Multi-AI Orchestrator set in AI Service');
    }

    setSecureTokenManager(tokenManager) {
        this.secureTokenManager = tokenManager;
        console.log('✅ Secure Token Manager set in AI Service');
    }

    /**
     * Get authentication token for API requests
     */
    async getAuthToken() {
        try {
            // Try multiple sources in priority order
            
            // 1. Check if token is passed via environment (from code-server session)
            if (process.env.VIGTHORIA_TOKEN) {
                console.log('[AI-SERVICE] 🔑 Using token from environment');
                return process.env.VIGTHORIA_TOKEN;
            }
            
            // 2. Try secure token manager (encrypted storage)
            if (this.secureTokenManager) {
                const tokenResult = await this.secureTokenManager.getUserToken();
                if (tokenResult && tokenResult.success && tokenResult.token) {
                    console.log('[AI-SERVICE] 🔑 Using token from SecureTokenManager');
                    return tokenResult.token;
                }
            }
            
            // 3. Try VS Code workspace settings
            const vscode = require('vscode');
            const config = vscode.workspace.getConfiguration('vigthoria');
            const configToken = config.get('apiToken');
            if (configToken) {
                console.log('[AI-SERVICE] 🔑 Using token from VS Code settings');
                return configToken;
            }
            
            // 4. Try to read from session file in workspace root
            try {
                const fs = require('fs');
                const path = require('path');
                const vscode = require('vscode');
                
                // Get workspace root folder
                const workspaceFolders = vscode.workspace.workspaceFolders;
                if (workspaceFolders && workspaceFolders.length > 0) {
                    const workspaceRoot = workspaceFolders[0].uri.fsPath;
                    const sessionFile = path.join(workspaceRoot, '.vigthoria-session');
                    
                    if (fs.existsSync(sessionFile)) {
                        const sessionData = JSON.parse(fs.readFileSync(sessionFile, 'utf8'));
                        if (sessionData.token) {
                            console.log('[AI-SERVICE] 🔑 Using token from workspace session file');
                            // Store in SecureTokenManager for future use
                            if (this.secureTokenManager) {
                                await this.secureTokenManager.storeUserToken(
                                    sessionData.userId,
                                    sessionData.username,
                                    sessionData.token
                                );
                                console.log('[AI-SERVICE] 💾 Token stored in SecureTokenManager');
                            }
                            return sessionData.token;
                        }
                    }
                }
            } catch (err) {
                console.warn('[AI-SERVICE] ⚠️ Could not read session file:', err.message);
            }
            
            console.warn('[AI-SERVICE] ⚠️ No authentication token found - requests may fail');
            return null;
        } catch (error) {
            console.error('[AI-SERVICE] ❌ Failed to get auth token:', error.message);
            return null;
        }
    }

    async initialize() {
        try {
            await this.checkConnection();
            console.log('🤖 AI Service initialized');
        } catch (error) {
            console.warn('⚠️ AI Service initialization failed, using fallback:', error);
        }
    }

    async checkConnection() {
        const targets = [
            { base: this.apiUrl, name: 'primary API' },
            { base: this.apiFallbackUrl, name: 'fallback API' }
        ].filter(target => Boolean(target.base));

        for (const target of targets) {
            // Use /health appended directly (not URL resolution which drops paths)
            const healthUrl = `${target.base.replace(/\/$/, '')}/health`;
            try {
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 8000);
                
                const response = await fetch(healthUrl, {
                    method: 'GET',
                    signal: controller.signal
                });
                
                clearTimeout(timeoutId);

                if (response.ok) {
                    if (this.apiUrl !== target.base) {
                        console.log(`🔄 Switching API base to ${target.base}`);
                    }
                    this.apiUrl = target.base.replace(/\/$/, '');
                    this.isConnected = true;
                    console.log(`✅ Connected to Vigthoria API (${target.name}) via ${healthUrl}`);
                    return true;
                }
            } catch (error) {
                console.warn(`⚠️ ${target.name} unreachable (${healthUrl}):`, error.message || error);
            }
        }

        // Even if health check fails, mark as connected so callMainAPI can try
        // The actual /route endpoint might still work
        this.isConnected = true;
        console.warn('⚠️ Health checks failed but allowing API calls to proceed');
        return true;
    }

    async processMessage(message, context = {}) {
        try {
            // Add to queue if needed
            if (this.processing) {
                return new Promise((resolve, reject) => {
                    this.requestQueue.push({ message, context, resolve, reject });
                });
            }

            this.processing = true;

            // Process based on mode
            const response = await this.processBasedOnMode(message, context);
            
            this.processing = false;
            this.processQueue();

            return response;

        } catch (error) {
            this.processing = false;
            this.processQueue();
            throw error;
        }
    }

    async processBasedOnMode(message, context) {
        const mode = context.mode || 'assistant';
        const modeConfig = AI_MODES[mode];

        if (!modeConfig) {
            throw new Error(`Unknown mode: ${mode}`);
        }

        switch (mode) {
            case 'ask':
                return await this.processAskMessage(message, context);
                
            case 'build':
                return await this.processBuildMessage(message, context);
                
            case 'agent':
                return await this.processAgentMessage(message, context);
                
            case 'chat':
                return await this.processChatMessage(message, context);
                
            case 'assistant':
                return await this.processAssistantMessage(message, context);
                
            case 'developer':
                return await this.processDeveloperMessage(message, context);
                
            case 'operator':
                return await this.processOperatorMessage(message, context);
                
            case 'autonomous':
                return await this.processAutonomousMessage(message, context);
                
            default:
                return await this.processGenericMessage(message, context);
        }
    }

    async processAskMessage(message, context) {
        // ASK mode routes through Model Router with 'conversation' task type
        const modeConfig = AI_MODES.ask;
        const preferredModel = context.model || (modeConfig.preferredModels || [])[0] || 'deepseek-r1:8b';
        
        try {
            return await this.callMainAPI(message, context, preferredModel, 'ask', 'conversation');
        } catch (error) {
            console.error('❌ ASK mode error:', error);
            // Return actual error info so user can diagnose
            return {
                content: `⚠️ Could not reach Vigthoria AI. Error: ${error.message || 'Unknown error'}. Please check your internet connection and try again.`,
                metadata: { model: 'error', mode: 'ask', offline: true, timestamp: new Date().toISOString() }
            };
        }
    }

    async processBuildMessage(message, context) {
        // BUILD mode routes through Model Router with 'code_generation' task type
        const modeConfig = AI_MODES.build;
        const preferredModel = context.model || (modeConfig.preferredModels || [])[0] || 'vigthoria-v3-code-35b';
        
        try {
            return await this.callMainAPI(message, context, preferredModel, 'build', 'code_generation');
        } catch (error) {
            console.error('❌ BUILD mode error:', error);
            return {
                content: `⚠️ Could not reach Vigthoria AI. Error: ${error.message || 'Unknown error'}. Please check your internet connection and try again.`,
                metadata: { model: 'error', mode: 'build', offline: true, timestamp: new Date().toISOString() }
            };
        }
    }

    async processAgentMessage(message, context) {
        const agentMessage = context.rawMessage || message;
        const routerPrompt = context.agentPrompt || message;
        const modeConfig = AI_MODES.agent;
        const preferredModel = context.model || (modeConfig.preferredModels || [])[0] || 'vigthoria-v3-code-35b';
        const allowModelRouterFallback = context.allowModelRouterFallback !== false;

        try {
            const v3Response = await this.runV3AgentWorkflow(agentMessage, context);

            return {
                content: v3Response.content,
                metadata: {
                    mode: 'agent',
                    source: 'v3-agent',
                    taskId: v3Response.taskId || null,
                    backendUrl: v3Response.backendUrl || null,
                    timestamp: new Date().toISOString()
                }
            };
        } catch (error) {
            console.warn('⚠️ V3 Agent primary path unavailable, falling back to standalone agent API:', error.message || error);
        }

        try {
            const agentResponse = await this.runAgentWorkflow(agentMessage, context);

            return {
                content: agentResponse.content,
                metadata: {
                    mode: 'agent',
                    source: 'agent-api',
                    workflowId: agentResponse.workflowId || null,
                    agentSystemUsed: agentResponse.agentSystemUsed || null,
                    timestamp: new Date().toISOString()
                }
            };
        } catch (error) {
            console.warn('⚠️ Agent API primary path unavailable, falling back to model router:', error.message || error);
        }

        if (!allowModelRouterFallback) {
            return {
                content: '⚠️ Vigthoria Agent backend is unavailable. Agent mode is pinned to the V3/agent workflow and will not fall back to the model router automatically.',
                metadata: {
                    mode: 'agent',
                    source: 'agent-backend-unavailable',
                    offline: true,
                    timestamp: new Date().toISOString()
                }
            };
        }

        try {
            const fallbackResponse = await this.callMainAPI(routerPrompt, context, preferredModel, 'agent', 'coding');
            return {
                ...fallbackResponse,
                metadata: {
                    ...(fallbackResponse.metadata || {}),
                    mode: 'agent',
                    source: 'model-router-fallback',
                    timestamp: new Date().toISOString()
                }
            };
        } catch (error) {
            console.error('❌ AGENT mode error:', error);
            return {
                content: `⚠️ Could not reach Vigthoria Agent backend. Error: ${error.message || 'Unknown error'}. Please check your internet connection and try again.`,
                metadata: { model: 'error', mode: 'agent', offline: true, timestamp: new Date().toISOString() }
            };
        }
    }

    getAgentServiceBaseUrl() {
        return (process.env.VIGTHORIA_AGENT_API_URL || 'http://127.0.0.1:8001').replace(/\/$/, '');
    }

    getV3AgentBaseUrls() {
        const urls = [
            process.env.VIGTHORIA_V3_AGENT_URL,
            process.env.V3_AGENT_URL,
            process.env.VIGTHORIA_V3_AGENT_FALLBACK_URL,
            'http://10.0.0.2:8030',
            'https://coder.vigthoria.io',
            'http://127.0.0.1:8030',
            'http://localhost:8030'
        ].filter(Boolean).map(url => url.replace(/\/$/, ''));

        return [...new Set(urls)];
    }

    getV3AgentRunUrl(baseUrl) {
        if (/127\.0\.0\.1:8030|localhost:8030/.test(baseUrl)) {
            return `${baseUrl}/api/agent/run`;
        }

        return `${baseUrl}/api/v3-agent/run`;
    }

    async getV3AgentHeaders() {
        const headers = {
            'Content-Type': 'application/json'
        };

        const authToken = await this.getAuthToken();
        if (authToken) {
            headers.Authorization = `Bearer ${authToken}`;
        }

        const serviceKey = process.env.VIGTHORIA_V3_SERVICE_KEY
            || process.env.V3_SERVICE_KEY
            || process.env.HYPERLOOP_SERVICE_KEY;

        if (serviceKey) {
            headers['X-Service-Key'] = serviceKey;
        }

        return headers;
    }

    buildV3AgentContext(context = {}) {
        const targetPath = this.resolveAgentTargetPath(context);
        return JSON.stringify({
            workspace: context.workspace || null,
            activeFile: context.activeFile || null,
            history: context.history || [],
            agentTaskType: context.agentTaskType || 'general',
            executionSurface: context.executionSurface || 'fork',
            clientSurface: context.clientSurface || 'fork',
            localMachineCapable: context.localMachineCapable !== false,
            workspacePath: context.workspacePath || targetPath,
            projectPath: context.projectPath || targetPath,
            targetPath
        });
    }

    async runV3AgentWorkflow(message, context = {}) {
        const headers = await this.getV3AgentHeaders();
        const timeoutMs = context.agentTimeoutMs || DEFAULT_V3_AGENT_TIMEOUT_MS;
        const expectedFiles = this.extractExpectedWorkspaceFiles(message, context);
        const preferRetry = /(premium|polished|landing|site|page|dashboard|saas|frontend|ui|responsive|animated|create the required project files and write them to the workspace)/i.test(String(message || ''));

        const maxAttempts = preferRetry ? 2 : 1;
        let lastErrors = [];

        for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
            const errors = [];

            for (const baseUrl of this.getV3AgentBaseUrls()) {
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

                try {
                    const response = await fetch(this.getV3AgentRunUrl(baseUrl), {
                        method: 'POST',
                        headers,
                        body: JSON.stringify({
                            request: message,
                            context: this.buildV3AgentContext(context),
                            stream: true
                        }),
                        signal: controller.signal
                    });

                    if (!response.ok) {
                        const errorText = await response.text().catch(() => '');
                        throw new Error(`V3 agent ${response.status}: ${errorText.slice(0, 200)}`);
                    }

                    const data = await this.collectV3AgentStream(response, context);
                    this.recoverAgentWorkspaceFiles(context, data.files || {}, expectedFiles);
                    await this.waitForAgentWorkspaceSettle(context, { expectedFiles });
                    await this.ensureAgentFrontendPolish(message, context);
                    return {
                        content: this.formatV3AgentResponse(data),
                        taskId: data.task_id || null,
                        backendUrl: baseUrl
                    };
                } catch (error) {
                    if (error && error.name === 'AbortError' && error.partialData && this.hasAgentWorkspaceOutput(context)) {
                        this.recoverAgentWorkspaceFiles(context, error.partialData.files || {}, expectedFiles);
                        await this.waitForAgentWorkspaceSettle(context, { expectedFiles });
                        await this.ensureAgentFrontendPolish(message, context);
                        return {
                            content: this.formatV3AgentResponse(error.partialData) || 'V3 agent wrote workspace files before the request timed out waiting for a final summary.',
                            taskId: error.partialData.task_id || null,
                            backendUrl: baseUrl,
                            partial: true,
                            metadata: { source: 'v3-agent', mode: 'agent', partial: true }
                        };
                    }
                    errors.push(`${baseUrl}: ${error.message || error}`);
                } finally {
                    clearTimeout(timeoutId);
                }
            }

            lastErrors = errors;
            const shouldRetry = attempt < maxAttempts
                && preferRetry
                && !this.hasAgentWorkspaceOutput(context)
                && errors.some((entry) => /terminated|abort|timed out|timeout|ECONNRESET|socket hang up/i.test(entry));
            if (!shouldRetry) {
                break;
            }

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

        throw new Error(lastErrors.join(' | '));
    }

    async waitForAgentWorkspaceSettle(context = {}, options = {}) {
        const fs = require('fs');
        const path = this.resolveAgentTargetPath(context);
        if (!path || !fs.existsSync(path)) {
            return;
        }

        const timeoutMs = options.timeoutMs || 15000;
        const pollMs = options.pollMs || 300;
        const stableMs = options.stableMs || 1200;
        const expectedFiles = Array.isArray(options.expectedFiles)
            ? options.expectedFiles.map((entry) => String(entry || '').trim()).filter(Boolean)
            : [];
        const start = Date.now();
        let stableSince = 0;
        let lastSignature = '';

        while (Date.now() - start < timeoutMs) {
            const snapshot = this.getAgentWorkspaceSnapshot(path);
            if (snapshot.fileCount === 0) {
                stableSince = 0;
                lastSignature = '';
                await new Promise((resolve) => setTimeout(resolve, pollMs));
                continue;
            }

            if (expectedFiles.length > 0 && !expectedFiles.every((filePath) => snapshot.paths.includes(filePath))) {
                stableSince = 0;
                lastSignature = snapshot.signature;
                await new Promise((resolve) => setTimeout(resolve, pollMs));
                continue;
            }

            if (snapshot.signature === lastSignature) {
                if (!stableSince) {
                    stableSince = Date.now();
                }
                if (Date.now() - stableSince >= stableMs) {
                    return;
                }
            } else {
                lastSignature = snapshot.signature;
                stableSince = Date.now();
            }

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

    getAgentWorkspaceSnapshot(rootPath) {
        const fs = require('fs');
        const path = require('path');
        const stack = [rootPath];
        let fileCount = 0;
        const entries = [];

        while (stack.length > 0) {
            const current = stack.pop();
            for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
                if (entry.name === '.git' || entry.name === 'node_modules') {
                    continue;
                }

                const fullPath = path.join(current, entry.name);
                if (entry.isDirectory()) {
                    stack.push(fullPath);
                    continue;
                }

                if (!entry.isFile()) {
                    continue;
                }

                fileCount += 1;
                const stat = fs.statSync(fullPath);
                entries.push(`${path.relative(rootPath, fullPath)}:${stat.size}:${stat.mtimeMs}`);
            }
        }

        entries.sort();
        return {
            fileCount,
            paths: entries.map((entry) => entry.split(':', 1)[0]),
            signature: entries.join('|')
        };
    }

    extractExpectedWorkspaceFiles(message = '', context = {}) {
        const candidates = new Set();
        const addMatches = (value) => {
            const text = String(value || '');
            const pattern = /`([^`]+\.(?:html|css|js|jsx|ts|tsx|json|md|py|sh))`/gi;
            let match;
            while ((match = pattern.exec(text)) !== null) {
                const filePath = match[1].trim().replace(/^\.\//, '');
                if (filePath) {
                    candidates.add(filePath);
                }
            }
        };

        addMatches(message);
        addMatches(context.rawMessage);
        addMatches(context.agentPrompt);
        return Array.from(candidates);
    }

    async ensureAgentFrontendPolish(message = '', context = {}) {
        const fs = require('fs');
        const path = require('path');
        const rootPath = this.resolveAgentTargetPath(context);
        if (!rootPath || !fs.existsSync(rootPath)) {
            return;
        }

        const prompt = String(message || '');
        if (!/(premium|polished|landing|site|page|dashboard|saas|frontend|ui)/i.test(prompt)) {
            return;
        }

        const htmlPath = path.join(rootPath, 'index.html');
        if (!fs.existsSync(htmlPath)) {
            return;
        }

        let html = fs.readFileSync(htmlPath, 'utf8');
        const ensuredAssets = this.ensureReferencedFrontendAssets(rootPath, html, prompt, 'Vigthoria Fork');
        html = ensuredAssets.html;
        const cssPath = ensuredAssets.cssPath;
        const jsPath = ensuredAssets.jsPath;
        if (html !== fs.readFileSync(htmlPath, 'utf8')) {
            fs.writeFileSync(htmlPath, `${html.trimEnd()}\n`, 'utf8');
        }
        if (!cssPath || !fs.existsSync(cssPath)) {
            return;
        }

        if (/(dashboard|saas|analytics|billing|team management)/i.test(prompt)) {
            const activeSectionHasDashboard = /<section[^>]*class=["'][^"']*active[^"']*["'][^>]*>[\s\S]*?\bDashboard\b/i.test(html);
            if (!activeSectionHasDashboard) {
                if (/<section[^>]+id=["']login["'][^>]*class=["'][^"']*active/i.test(html)) {
                    html = html.replace(/(<section[^>]+id=["']login["'][^>]*class=["'][^"']*active[^"']*["'][^>]*>[\s\S]*?<h[12][^>]*>.*?<\/h[12]>)/i, '$1\n                <p class="vigthoria-runtime-label">Dashboard preview with analytics, billing, and team controls.</p>');
                } else if (/<main[^>]*>/i.test(html)) {
                    html = html.replace(/<main([^>]*)>/i, '<main$1>\n            <p class="vigthoria-runtime-label">Dashboard preview with analytics, billing, and team controls.</p>');
                }

                fs.writeFileSync(htmlPath, `${html.trimEnd()}\n`, 'utf8');
            }
        }

        const css = fs.readFileSync(cssPath, 'utf8');
        const js = fs.existsSync(jsPath) ? fs.readFileSync(jsPath, 'utf8') : '';
        const combined = `${html}\n${css}\n${js}`;

        if (!/@media|matchMedia|mobile-nav|hamburger|menu-toggle/i.test(combined)) {
            fs.appendFileSync(cssPath, `\n\n/* Vigthoria Fork Responsive Baseline */\n@media (max-width: 900px) {\n    .nav-links, .nav-list, nav ul {\n        display: none;\n        flex-direction: column;\n        gap: 0.75rem;\n    }\n\n    .nav-links.is-open, .nav-list.is-open, nav ul.is-open {\n        display: flex;\n    }\n\n    .mobile-nav-toggle, #menu-toggle, .menu-toggle {\n        display: inline-flex;\n    }\n}\n`);
        }

        if (/keyframes|animation|transition|IntersectionObserver/i.test(combined)) {
            return;
        }

        const cssMarker = '/* Vigthoria Fork Motion Enhancement */';
        const jsMarker = '/* Vigthoria Fork Motion Enhancement */';
        if (!/\.vigthoria-runtime-label\s*\{/i.test(css)) {
            fs.appendFileSync(cssPath, `\n\n.vigthoria-runtime-label {\n    margin: 0 0 1rem;\n    font-size: 0.95rem;\n    font-weight: 600;\n    letter-spacing: 0.04em;\n    text-transform: uppercase;\n    color: #8f3f19;\n}\n`);
        }
        if (!css.includes(cssMarker)) {
            fs.appendFileSync(cssPath, `\n\n${cssMarker}\n.hero, section {\n    opacity: 0;\n    transform: translateY(24px);\n    animation: vigForkFadeIn 0.8s ease forwards;\n}\n\nsection {\n    animation-delay: 0.12s;\n}\n\n#menu-toggle, .cta, a {\n    transition: transform 0.25s ease, opacity 0.25s ease;\n}\n\n#menu-toggle:hover, .cta:hover, a:hover {\n    transform: translateY(-2px);\n}\n\n.motion-reveal {\n    opacity: 0;\n    transform: translateY(24px);\n    transition: opacity 0.7s ease, transform 0.7s ease;\n}\n\n.motion-reveal.is-visible {\n    opacity: 1;\n    transform: translateY(0);\n}\n\n@keyframes vigForkFadeIn {\n    from {\n        opacity: 0;\n        transform: translateY(24px);\n    }\n    to {\n        opacity: 1;\n        transform: translateY(0);\n    }\n}\n`);
        }

        if (!js.includes(jsMarker)) {
            fs.appendFileSync(jsPath, `\n\n${jsMarker}\ndocument.addEventListener('DOMContentLoaded', () => {\n    const revealTargets = document.querySelectorAll('section, .hero, .project-grid > *, .journal-preview > *');\n    if (typeof IntersectionObserver !== 'function') {\n        revealTargets.forEach((element) => element.classList.add('is-visible'));\n        return;\n    }\n\n    const observer = new IntersectionObserver((entries) => {\n        entries.forEach((entry) => {\n            if (entry.isIntersecting) {\n                entry.target.classList.add('is-visible');\n                observer.unobserve(entry.target);\n            }\n        });\n    }, { threshold: 0.16 });\n\n    revealTargets.forEach((element, index) => {\n        element.classList.add('motion-reveal');\n        element.style.transitionDelay = String(Math.min(index * 60, 320)) + 'ms';\n        observer.observe(element);\n    });\n});\n`);
        }
    }

    ensureReferencedFrontendAssets(rootPath, html, prompt, surfaceLabel) {
        const fs = require('fs');
        const path = require('path');
        const localAssetPath = (rawPath) => {
            const candidate = String(rawPath || '').trim();
            if (!candidate || /^https?:\/\//i.test(candidate) || /^data:/i.test(candidate) || candidate.startsWith('#')) {
                return '';
            }

            return candidate.split('?')[0].split('#')[0].replace(/^\//, '');
        };

        const ensureTextAsset = (relativePath, content) => {
            const normalized = localAssetPath(relativePath);
            if (!normalized) {
                return '';
            }

            const absolutePath = path.join(rootPath, normalized);
            if (!fs.existsSync(absolutePath)) {
                fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
                fs.writeFileSync(absolutePath, content, 'utf8');
            }
            return absolutePath;
        };

        const cssRefs = Array.from(html.matchAll(/<link[^>]+href=["']([^"']+\.css(?:\?[^"']*)?)["']/gi))
            .map((match) => localAssetPath(match[1]))
            .filter(Boolean);
        const jsRefs = Array.from(html.matchAll(/<script[^>]+src=["']([^"']+\.(?:js|mjs)(?:\?[^"']*)?)["']/gi))
            .map((match) => localAssetPath(match[1]))
            .filter(Boolean);

        let cssPath = cssRefs.map((ref) => path.join(rootPath, ref)).find((candidate) => fs.existsSync(candidate)) || '';
        let jsPath = jsRefs.map((ref) => path.join(rootPath, ref)).find((candidate) => fs.existsSync(candidate)) || '';

        const cssTemplate = this.buildFallbackFrontendCss(surfaceLabel);
        const jsTemplate = this.buildFallbackFrontendJs(surfaceLabel);

        if (!cssPath && cssRefs.length > 0) {
            cssPath = ensureTextAsset(cssRefs[0], cssTemplate);
        }

        if (!jsPath && jsRefs.length > 0) {
            jsPath = ensureTextAsset(jsRefs[0], jsTemplate);
        }

        if (!cssPath) {
            cssPath = ensureTextAsset('styles.css', cssTemplate);
            if (cssPath && !/<link[^>]+href=["'][^"']*styles\.css/i.test(html)) {
                html = /<\/head>/i.test(html)
                    ? html.replace(/<\/head>/i, '    <link rel="stylesheet" href="styles.css">\n</head>')
                    : html;
            }
        }

        if (!jsPath && /(premium|polished|landing|site|page|dashboard|saas|frontend|ui|responsive|animated)/i.test(prompt)) {
            jsPath = ensureTextAsset('scripts.js', jsTemplate);
            if (jsPath && !/<script[^>]+src=["'][^"']*scripts\.js/i.test(html)) {
                html = /<\/body>/i.test(html)
                    ? html.replace(/<\/body>/i, '    <script src="scripts.js"></script>\n</body>')
                    : `${html.trimEnd()}\n<script src="scripts.js"></script>\n`;
            }
        }

        return {
            html,
            cssPath,
            jsPath: jsPath || path.join(rootPath, 'scripts.js')
        };
    }

    buildFallbackFrontendCss(surfaceLabel) {
        return `/* ${surfaceLabel} Frontend Baseline */
:root {
    color-scheme: light;
    --bg: #f4efe5;
    --surface: rgba(255, 255, 255, 0.82);
    --text: #1f2933;
    --muted: #52606d;
    --accent: #c36f3c;
    --accent-strong: #8f3f19;
    --border: rgba(31, 41, 51, 0.12);
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: "Georgia", "Times New Roman", serif;
    color: var(--text);
    background: radial-gradient(circle at top, rgba(195, 111, 60, 0.18), transparent 42%), var(--bg);
}

header, nav, main, section, footer {
    width: 100%;
}

.container, .shell, .content {
    width: min(1120px, calc(100% - 2rem));
    margin: 0 auto;
}

.hero, section, footer {
    opacity: 0;
    transform: translateY(24px);
    animation: vigForkFallbackFadeIn 0.8s ease forwards;
}

.hero {
    min-height: 72vh;
    padding: 6rem 0 4rem;
}

.nav-list, nav ul {
    display: flex;
    gap: 1rem;
    list-style: none;
    padding: 0;
    margin: 0;
}

.mobile-nav-toggle, #menu-toggle, .menu-toggle {
    display: none;
}

.cta, button, a {
    transition: transform 0.25s ease, opacity 0.25s ease, background-color 0.25s ease;
}

.cta:hover, button:hover, a:hover {
    transform: translateY(-2px);
}

.motion-reveal {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 0.7s ease, transform 0.7s ease;
}

.motion-reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
}

@media (max-width: 900px) {
    .nav-list, nav ul {
        display: none;
        flex-direction: column;
        padding: 1rem;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: 1rem;
    }

    .nav-list.is-open, nav ul.is-open {
        display: flex;
    }

    .mobile-nav-toggle, #menu-toggle, .menu-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

@keyframes vigForkFallbackFadeIn {
    from {
        opacity: 0;
        transform: translateY(24px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}
`;
    }

    buildFallbackFrontendJs(surfaceLabel) {
        return `/* ${surfaceLabel} Frontend Baseline */
document.addEventListener('DOMContentLoaded', () => {
    const toggle = document.querySelector('.mobile-nav-toggle, #menu-toggle, .menu-toggle');
    const nav = document.querySelector('.nav-list, nav ul');
    if (toggle && nav) {
        toggle.addEventListener('click', () => {
            nav.classList.toggle('is-open');
        });
    }

    const revealTargets = document.querySelectorAll('section, .hero, .card, article, .project-grid > *, .journal-preview > *');
    if (typeof IntersectionObserver !== 'function') {
        revealTargets.forEach((element) => element.classList.add('is-visible'));
        return;
    }

    const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
            if (entry.isIntersecting) {
                entry.target.classList.add('is-visible');
                observer.unobserve(entry.target);
            }
        });
    }, { threshold: 0.16 });

    revealTargets.forEach((element) => {
        element.classList.add('motion-reveal');
        observer.observe(element);
    });
});
`;
    }

    async collectV3AgentStream(response, context = {}) {
        if (!response.body || typeof response.body.getReader !== 'function') {
            return response.json();
        }

        const reader = response.body.getReader();
        const decoder = new TextDecoder();
        let buffer = '';
        const events = [];
        let final = null;
        const streamedFiles = {};
        const idleTimeoutMs = context.agentIdleTimeoutMs || DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS;

        while (true) {
            let chunk;
            try {
                const readPromise = reader.read();

                while (true) {
                    const timeoutSentinel = Symbol('v3-agent-idle-timeout');
                    const result = idleTimeoutMs > 0
                        ? await Promise.race([
                            readPromise,
                            new Promise((resolve) => {
                                setTimeout(() => resolve(timeoutSentinel), idleTimeoutMs);
                            })
                        ])
                        : await readPromise;

                    if (result !== timeoutSentinel) {
                        chunk = result;
                        break;
                    }

                    if (this.hasAgentWorkspaceOutput(context)) {
                        const stalledError = new Error('V3 agent stream stalled after writing workspace output');
                        stalledError.name = 'AbortError';
                        stalledError.partialData = {
                            task_id: events.find(event => event && event.task_id)?.task_id || null,
                            result: final,
                            events,
                            files: streamedFiles,
                        };
                        throw stalledError;
                    }
                }
            } catch (error) {
                if (error && error.name === 'AbortError') {
                    error.partialData = {
                        task_id: events.find(event => event && event.task_id)?.task_id || null,
                        result: final,
                        events,
                        files: streamedFiles,
                    };
                }
                throw error;
            }

            const { done, value } = chunk;
            if (done) {
                break;
            }

            buffer += decoder.decode(value, { stream: true });
            const lines = buffer.split('\n');
            buffer = lines.pop() || '';

            for (const line of lines) {
                if (!line.startsWith('data: ')) {
                    continue;
                }

                const payload = line.slice(6).trim();
                if (!payload || payload === '[DONE]') {
                    continue;
                }

                const event = JSON.parse(payload);
                events.push(event);
                this.captureV3AgentStreamMutation(event, streamedFiles);

                if (event.type === 'error') {
                    if (this.hasAgentWorkspaceOutput(context)) {
                        return {
                            task_id: events.find(entry => entry && entry.task_id)?.task_id || null,
                            result: final || event,
                            events,
                            files: streamedFiles,
                            partial: true,
                        };
                    }
                    throw new Error(event.message || 'V3 agent returned an error');
                }

                if (event.type === 'complete' || event.type === 'message') {
                    final = event;
                }
            }
        }

        return {
            task_id: events.find(event => event && event.task_id)?.task_id || null,
            result: final,
            events,
            files: streamedFiles,
        };
    }

    captureV3AgentStreamMutation(event, streamedFiles) {
        if (!event || event.type !== 'tool_call' || !streamedFiles) {
            return;
        }

        const args = event.arguments || {};
        if ((event.name === 'write_file' || event.name === 'edit_file') && typeof args.path === 'string') {
            const filePath = args.path.trim().replace(/\\/g, '/').replace(/^.*\//, '');
            if (!filePath) {
                return;
            }

            if (event.name === 'write_file' && typeof args.content === 'string') {
                streamedFiles[filePath] = args.content;
                return;
            }

            if (event.name === 'edit_file' && typeof args.old_string === 'string' && typeof args.new_string === 'string') {
                const existing = streamedFiles[filePath];
                if (typeof existing === 'string' && existing.includes(args.old_string)) {
                    streamedFiles[filePath] = existing.replace(args.old_string, args.new_string);
                }
            }
        }

        if (event.name === 'deploy_project' && typeof args.source_path === 'string') {
            streamedFiles['__deploy__'] = JSON.stringify({
                source: args.source_path,
                subdomain: args.subdomain || null,
                result: event.result || null
            });
        }
    }

    recoverAgentWorkspaceFiles(context = {}, streamedFiles = {}, expectedFiles = []) {
        const fs = require('fs');
        const path = require('path');
        const rootPath = this.resolveAgentTargetPath(context);
        if (!rootPath || !fs.existsSync(rootPath) || !streamedFiles || Object.keys(streamedFiles).length === 0) {
            return;
        }

        const targets = Array.isArray(expectedFiles) && expectedFiles.length > 0
            ? expectedFiles
            : Object.keys(streamedFiles);

        for (const relativePath of targets) {
            const content = streamedFiles[relativePath];
            if (typeof content !== 'string') {
                continue;
            }

            const absolutePath = path.join(rootPath, relativePath);
            if (fs.existsSync(absolutePath)) {
                continue;
            }

            fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
            fs.writeFileSync(absolutePath, content, 'utf8');
        }
    }

    hasAgentWorkspaceOutput(context = {}) {
        try {
            const fs = require('fs');
            const path = this.resolveAgentTargetPath(context);
            if (!path || !fs.existsSync(path)) {
                return false;
            }

            const stack = [path];
            while (stack.length > 0) {
                const current = stack.pop();
                const entries = fs.readdirSync(current, { withFileTypes: true });
                for (const entry of entries) {
                    if (entry.name === '.git' || entry.name === 'node_modules') {
                        continue;
                    }

                    const fullPath = require('path').join(current, entry.name);
                    if (entry.isFile()) {
                        return true;
                    }
                    if (entry.isDirectory()) {
                        stack.push(fullPath);
                    }
                }
            }
        } catch (error) {
            console.warn('[AI-SERVICE] Failed to inspect agent workspace output:', error.message || error);
        }

        return false;
    }

    formatV3AgentResponse(data) {
        const result = data.result || {};

        if (typeof result === 'string') {
            return result;
        }

        if (typeof result.summary === 'string' && result.summary.trim()) {
            return result.summary;
        }

        if (typeof result.message === 'string' && result.message.trim()) {
            return result.message;
        }

        if (Array.isArray(data.events)) {
            const completionEvent = [...data.events].reverse().find(event => event && event.type === 'complete' && typeof event.summary === 'string');
            if (completionEvent) {
                return completionEvent.summary;
            }

            const messageEvent = [...data.events].reverse().find(event => event && event.type === 'message' && typeof event.content === 'string');
            if (messageEvent) {
                return messageEvent.content;
            }
        }

        const text = JSON.stringify(data, null, 2);
        return text.length > 12000 ? `${text.slice(0, 12000)}\n\n[V3 agent output truncated]` : text;
    }

    getAgentWorkflowProfile(context = {}) {
        const taskType = context.agentTaskType || 'general';

        switch (taskType) {
            case 'analysis':
            case 'planning':
                return {
                    taskType: 'analysis',
                    agentSystem: 'bmad',
                    priority: 'high'
                };
            case 'debugging':
                return {
                    taskType: 'debugging',
                    agentSystem: 'vigthoria',
                    priority: 'high'
                };
            case 'implementation':
            case 'refactoring':
            case 'deployment':
                return {
                    taskType: 'coding',
                    agentSystem: 'vigthoria',
                    priority: 'high'
                };
            default:
                return {
                    taskType: 'general',
                    agentSystem: 'auto',
                    priority: 'normal'
                };
        }
    }

    resolveAgentTargetPath(context = {}) {
        const workspace = context.workspace || {};
        if (workspace.path) {
            return workspace.path;
        }
        if (workspace.workspacePath) {
            return workspace.workspacePath;
        }
        if (workspace.workspaceFolder) {
            return workspace.workspaceFolder;
        }
        if (context.activeFile && context.activeFile.fullPath) {
            const path = require('path');
            return path.dirname(context.activeFile.fullPath);
        }

        return process.cwd();
    }

    async runAgentWorkflow(message, context = {}) {
        const baseUrl = this.getAgentServiceBaseUrl();
        const workflowProfile = this.getAgentWorkflowProfile(context);
        const controller = new AbortController();
        const timeoutMs = context.agentTimeoutMs || 600000;
        const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

        try {
            const response = await fetch(`${baseUrl}/api/workflow/execute`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    description: message,
                    task_type: workflowProfile.taskType,
                    agent_system: workflowProfile.agentSystem,
                    priority: workflowProfile.priority,
                    target_path: this.resolveAgentTargetPath(context),
                    context: {
                        workspace: context.workspace || null,
                        activeFile: context.activeFile || null,
                        history: context.history || []
                    }
                }),
                signal: controller.signal
            });

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

            const data = await response.json();
            if (!data.success) {
                throw new Error(data.error || 'Agent workflow execution failed');
            }

            return {
                content: this.formatAgentWorkflowResponse(data),
                workflowId: data.workflow_id || null,
                agentSystemUsed: data.agent_system_used || workflowProfile.agentSystem
            };
        } finally {
            clearTimeout(timeoutId);
        }
    }

    formatAgentWorkflowResponse(data) {
        const result = data.result || {};

        if (typeof result === 'string') {
            return result;
        }

        if (result.summary) {
            return result.summary;
        }

        if (result.results) {
            const text = JSON.stringify(result.results, null, 2);
            return text.length > 12000 ? `${text.slice(0, 12000)}\n\n[Agent workflow output truncated]` : text;
        }

        const text = JSON.stringify(result, null, 2);
        return text.length > 12000 ? `${text.slice(0, 12000)}\n\n[Agent workflow output truncated]` : text;
    }

    async delegateToExternalService(message, context, endpoint, mode) {
        const payload = {
            model: "llama3:8b-instruct-q4_0",
            prompt: message,
            stream: false
        };

        const response = await fetch(`${endpoint}/api/process`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
            timeout: 60000
        });

        if (!response.ok) {
            throw new Error(`External service error: ${response.status}`);
        }

        const data = await response.json();
        return {
            content: data.response || data.content || 'No response from external service',
            metadata: {
                mode: mode,
                source: 'external-service',
                endpoint: endpoint,
                timestamp: new Date().toISOString()
            }
        };
    }

    async processWithOllama(message, context, model, mode) {
        // Try local Ollama first, then server Ollama
        try {
            return await this.callLocalOllama(message, context, model, mode);
        } catch (error) {
            console.warn('⚠️ Local Ollama failed, trying server:', error.message);
            return await this.callServerOllama(message, context, model, mode);
        }
    }

    async callLocalOllama(message, context, model, mode) {
        const payload = {
            model: model || 'llama3:8b-instruct-q4_0',
            prompt: this.buildContextAwarePrompt(message, context, mode),
            stream: false
        };

        const ollamaUrl = CONFIG.server.services.ollama || 'https://coder.vigthoria.io/api/ollama';
        const response = await fetch(`${ollamaUrl}/api/generate`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
            timeout: 30000
        });

        if (!response.ok) {
            throw new Error(`Local Ollama error: ${response.status}`);
        }

        const data = await response.json();
        return {
            content: data.response || 'No response from local Ollama',
            metadata: {
                model: model || 'llama3:8b-instruct-q4_0',
                mode: mode,
                source: 'local-ollama',
                timestamp: new Date().toISOString()
            }
        };
    }

    async callServerOllama(message, context, model, mode) {
        const payload = {
            model: model || 'llama3:8b-instruct-q4_0',
            prompt: message,
            stream: false
        };

        const ollamaUrl = CONFIG.server.services.ollama || 'https://coder.vigthoria.io/api/ollama';
        const response = await fetch(`${ollamaUrl}/api/generate`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
            timeout: 45000
        });

        if (!response.ok) {
            throw new Error(`Server Ollama error: ${response.status}`);
        }

        const data = await response.json();
        return {
            content: data.response || 'No response from server Ollama',
            metadata: {
                model: model || 'llama3:8b-instruct-q4_0',
                mode: mode,
                source: 'server-ollama',
                timestamp: new Date().toISOString()
            }
        };
    }

    async processChatMessage(message, context) {
        // Chat mode routes through Model Router with 'conversation' task type
        const preferredModel = context.model || 'deepseek-r1:8b';
        try {
            return await this.callMainAPI(message, context, preferredModel, 'chat', 'conversation');
        } catch (error) {
            console.error('❌ CHAT mode error:', error);
            return { content: `⚠️ Could not reach Vigthoria AI. Error: ${error.message || 'Unknown'}. Please try again.`, metadata: { mode: 'chat', offline: true, timestamp: new Date().toISOString() } };
        }
    }

    async processAssistantMessage(message, context) {
        // Assistant mode routes through Model Router with 'conversation' task type
        const preferredModel = context.model || 'deepseek-r1:8b';
        try {
            return await this.callMainAPI(message, context, preferredModel, 'assistant', 'conversation');
        } catch (error) {
            console.error('❌ ASSISTANT mode error:', error);
            return { content: `⚠️ Could not reach Vigthoria AI. Error: ${error.message || 'Unknown'}. Please try again.`, metadata: { mode: 'assistant', offline: true, timestamp: new Date().toISOString() } };
        }
    }

    async processDeveloperMessage(message, context) {
        // Developer mode routes through Model Router with 'coding' task type
        const preferredModel = context.model || 'vigthoria-v3-code-35b';
        try {
            return await this.callMainAPI(message, context, preferredModel, 'developer', 'coding');
        } catch (error) {
            console.error('❌ DEVELOPER mode error:', error);
            return { content: `⚠️ Could not reach Vigthoria AI. Error: ${error.message || 'Unknown'}. Please try again.`, metadata: { mode: 'developer', offline: true, timestamp: new Date().toISOString() } };
        }
    }

    async processOperatorMessage(message, context) {
        const bmadMessage = context.rawMessage || message;
        const routerPrompt = context.operatorPrompt || message;
        const modeConfig = AI_MODES.operator;
        const preferredModel = context.model || (modeConfig.preferredModels || [])[0] || 'vigthoria-v3-code-35b';
        const allowModelRouterFallback = context.allowModelRouterFallback !== false;

        try {
            const bmadResponse = await this.bmadConnector.processOperatorMessage(bmadMessage, context);

            if (bmadResponse && bmadResponse.success) {
                return {
                    content: bmadResponse.response,
                    metadata: {
                        mode: 'operator',
                        source: 'bmad',
                        operationType: bmadResponse.operationType,
                        taskId: bmadResponse.taskId || null,
                        workflowId: bmadResponse.workflowId || null,
                        timestamp: new Date().toISOString()
                    }
                };
            }
        } catch (error) {
            console.warn('⚠️ BMAD primary path unavailable, falling back to model router:', error.message || error);
        }

        if (!allowModelRouterFallback) {
            return {
                content: '⚠️ Vigthoria Operator backend is unavailable. Operator mode is pinned to BMAD and will not fall back to the model router automatically.',
                metadata: {
                    mode: 'operator',
                    source: 'operator-backend-unavailable',
                    offline: true,
                    timestamp: new Date().toISOString()
                }
            };
        }

        try {
            const fallbackResponse = await this.callMainAPI(routerPrompt, context, preferredModel, 'operator', 'analysis');

            return {
                ...fallbackResponse,
                metadata: {
                    ...(fallbackResponse.metadata || {}),
                    mode: 'operator',
                    source: 'model-router-fallback',
                    timestamp: new Date().toISOString()
                }
            };
        } catch (error) {
            console.error('❌ OPERATOR mode error:', error);
            return { content: `⚠️ Could not reach Vigthoria Operator backend. Error: ${error.message || 'Unknown'}. Please try again.`, metadata: { mode: 'operator', offline: true, timestamp: new Date().toISOString() } };
        }
    }

    async processAutonomousMessage(message, context) {
        // Autonomous mode routes through Model Router with 'coding' task type
        const preferredModel = context.model || 'vigthoria-v3-code-35b';
        try {
            return await this.callMainAPI(message, context, preferredModel, 'autonomous', 'coding');
        } catch (error) {
            console.error('❌ AUTONOMOUS mode error:', error);
            return { content: `⚠️ Could not reach Vigthoria AI. Error: ${error.message || 'Unknown'}. Please try again.`, metadata: { mode: 'autonomous', offline: true, timestamp: new Date().toISOString() } };
        }
    }

    async processGenericMessage(message, context) {
        // Generic mode routes through Model Router with 'conversation' task type
        const preferredModel = context.model || 'deepseek-r1:8b';
        try {
            return await this.callMainAPI(message, context, preferredModel, 'generic', 'conversation');
        } catch (error) {
            console.error('❌ Generic mode error:', error);
            return { content: `⚠️ Could not reach Vigthoria AI. Error: ${error.message || 'Unknown'}. Please try again.`, metadata: { mode: 'generic', offline: true, timestamp: new Date().toISOString() } };
        }
    }

    async sendToServer(endpoint, payload, retrying = false) {
        if (!this.isConnected) {
            await this.checkConnection();
        }

        try {
            // Get authentication token
            const authToken = await this.getAuthToken();
            
            // Use string concat to avoid URL path resolution issues
            const targetUrl = `${this.apiUrl.replace(/\/$/, '')}/${endpoint.replace(/^\//, '')}`;
            const headers = {
                'Content-Type': 'application/json',
                'User-Agent': 'Vigthoria-VSCode-Extension/2.0.0'
            };
            
            // Add authorization header if token available
            if (authToken) {
                headers['Authorization'] = `Bearer ${authToken}`;
            }
            
            const response = await fetch(targetUrl, {
                method: 'POST',
                headers: headers,
                body: JSON.stringify(payload),
                timeout: CONFIG.ai.timeout
            });

            if (!response.ok) {
                throw new Error(`Server error: ${response.status} ${response.statusText}`);
            }
            const data = await response.json();
            
            if (data.error) {
                throw new Error(data.error);
            }

            return {
                content: data.response || data.content || 'No response received',
                metadata: {
                    model: data.model || CONFIG.ai.model,
                    processingTime: data.processingTime,
                    tokensUsed: data.tokensUsed,
                    mode: payload.mode,
                    timestamp: new Date().toISOString()
                }
            };

        } catch (error) {
            console.error('❌ Server request failed:', error);
            if (!retrying && this.apiFallbackUrl && this.apiUrl !== this.apiFallbackUrl) {
                console.warn('🔁 Retrying request with fallback API endpoint');
                this.apiUrl = this.apiFallbackUrl;
                this.isConnected = false;
                return this.sendToServer(endpoint, payload, true);
            }

            const message = payload.message || payload.prompt || '';
            return this.getFallbackResponse(message, payload.mode);
        }
    }

    getFallbackResponse(message, mode) {
        const responses = {
            ask: "I'm currently unable to connect to Vigthoria AI services. Please check your internet connection and try again.",
            build: "Vigthoria AI services are temporarily unavailable. Please check your connection and try again.",
            agent: "Vigthoria AI is temporarily unavailable. Please check your connection and try again.",
            chat: "I'm currently unable to connect to Vigthoria AI. Please check your internet connection and try again.",
            assistant: "Vigthoria AI services are temporarily unavailable. Please try again in a moment.",
            developer: "Vigthoria AI services are temporarily unavailable. Please check your connection and try again.",
            operator: "Vigthoria AI services are temporarily unavailable. Please check your connection and try again.",
            autonomous: "Vigthoria AI services are temporarily unavailable. Please try again in a moment."
        };

        return {
            content: responses[mode] || responses.chat,
            metadata: {
                model: 'fallback',
                mode: mode,
                offline: true,
                timestamp: new Date().toISOString()
            }
        };
    }

    async getWorkspaceContext() {
        try {
            const vscode = require('vscode');
            const workspaceFolders = vscode.workspace.workspaceFolders;
            
            if (!workspaceFolders || workspaceFolders.length === 0) {
                return null;
            }

            return {
                name: workspaceFolders[0].name,
                path: workspaceFolders[0].uri.fsPath,
                fileCount: await this.getFileCount(workspaceFolders[0].uri.fsPath)
            };
        } catch (error) {
            console.warn('⚠️ Could not get workspace context:', error);
            return null;
        }
    }

    async getActiveFileContext() {
        try {
            const vscode = require('vscode');
            const activeEditor = vscode.window.activeTextEditor;
            
            if (!activeEditor) {
                return null;
            }

            return {
                fileName: activeEditor.document.fileName,
                language: activeEditor.document.languageId,
                lineCount: activeEditor.document.lineCount,
                selection: activeEditor.selection,
                content: activeEditor.document.getText()
            };
        } catch (error) {
            console.warn('⚠️ Could not get active file context:', error);
            return null;
        }
    }

    async detectProjectType() {
        try {
            const fs = require('fs');
            const path = require('path');
            const vscode = require('vscode');
            const workspaceFolders = vscode.workspace.workspaceFolders;
            
            if (!workspaceFolders || workspaceFolders.length === 0) {
                return 'unknown';
            }

            const rootPath = workspaceFolders[0].uri.fsPath;
            
            // Check for common project files
            if (fs.existsSync(path.join(rootPath, 'package.json'))) {
                const packageJson = JSON.parse(fs.readFileSync(path.join(rootPath, 'package.json'), 'utf8'));
                if (packageJson.dependencies?.react) return 'react';
                if (packageJson.dependencies?.vue) return 'vue';
                if (packageJson.dependencies?.['@angular/core']) return 'angular';
                return 'node';
            }
            
            if (fs.existsSync(path.join(rootPath, 'requirements.txt')) || 
                fs.existsSync(path.join(rootPath, 'setup.py'))) {
                return 'python';
            }
            
            if (fs.existsSync(path.join(rootPath, 'pom.xml'))) {
                return 'java';
            }
            
            if (fs.existsSync(path.join(rootPath, 'Cargo.toml'))) {
                return 'rust';
            }
            
            if (fs.existsSync(path.join(rootPath, 'go.mod'))) {
                return 'go';
            }

            return 'unknown';
        } catch (error) {
            console.warn('⚠️ Could not detect project type:', error);
            return 'unknown';
        }
    }

    async getCodeContext() {
        // Simplified code context - would be expanded in real implementation
        try {
            const activeFile = await this.getActiveFileContext();
            if (!activeFile) return null;

            return {
                currentFile: activeFile,
                projectType: await this.detectProjectType(),
                // Add more context as needed
            };
        } catch (error) {
            console.warn('⚠️ Could not get code context:', error);
            return null;
        }
    }

    async getSystemInfo() {
        try {
            const os = require('os');
            return {
                platform: os.platform(),
                arch: os.arch(),
                nodeVersion: process.version,
                memory: {
                    total: os.totalmem(),
                    free: os.freemem()
                }
            };
        } catch (error) {
            console.warn('⚠️ Could not get system info:', error);
            return null;
        }
    }

    async getFullProjectAnalysis() {
        // This would be a comprehensive project analysis
        return {
            workspace: await this.getWorkspaceContext(),
            projectType: await this.detectProjectType(),
            codeMetrics: await this.getCodeMetrics(),
            dependencies: await this.getDependencies()
        };
    }

    async getCodeMetrics() {
        // Simplified metrics
        return {
            totalFiles: 0,
            linesOfCode: 0,
            complexity: 'unknown'
        };
    }

    async getDependencies() {
        // Simplified dependency analysis
        return {
            production: [],
            development: [],
            security: 'unknown'
        };
    }

    getAutonomousCapabilities(subscription) {
        const tier = subscription?.tier || 'basic';
        
        const capabilities = {
            basic: ['read_files', 'basic_analysis'],
            premium: ['read_files', 'basic_analysis', 'code_generation', 'refactoring'],
            enterprise: ['all']
        };

        return capabilities[tier] || capabilities.basic;
    }

    async getFileCount(dirPath) {
        try {
            const fs = require('fs');
            const files = fs.readdirSync(dirPath);
            return files.length;
        } catch (error) {
            return 0;
        }
    }

    processQueue() {
        if (this.requestQueue.length > 0 && !this.processing) {
            const next = this.requestQueue.shift();
            this.processMessage(next.message, next.context)
                .then(next.resolve)
                .catch(next.reject);
        }
    }

    dispose() {
        this.requestQueue = [];
        this.processing = false;
        this.isConnected = false;
        console.log('🤖 AI Service disposed');
    }

    buildContextAwarePrompt(message, context, mode) {
        // Build workspace context section
        let workspaceSection = '';
        if (context && context.workspace) {
            const ws = context.workspace;
            workspaceSection = `\n## Workspace Context\n`;
            workspaceSection += `- **Project name:** ${ws.name || 'Unknown'}\n`;
            workspaceSection += `- **Project type:** ${ws.projectType || 'Unknown'}\n`;
            workspaceSection += `- **Root path:** ${ws.path || 'Unknown'}\n`;
            if (ws.fileTree) {
                workspaceSection += `\n### File Structure:\n\`\`\`\n${ws.fileTree}\n\`\`\`\n`;
            }
        }

        // Build active file context section
        let activeFileSection = '';
        if (context && context.activeFile) {
            const af = context.activeFile;
            activeFileSection = `\n## Currently Open File\n`;
            activeFileSection += `- **File:** ${af.fileName || af.fullPath || 'Unknown'}\n`;
            activeFileSection += `- **Language:** ${af.language || 'Unknown'}\n`;
            activeFileSection += `- **Lines:** ${af.lineCount || 0}\n`;
            if (af.hasSelection && af.selectedText) {
                activeFileSection += `\n### Selected Code:\n\`\`\`${af.language || ''}\n${af.selectedText.substring(0, 2000)}\n\`\`\`\n`;
            } else if (af.contentSnippet) {
                activeFileSection += `\n### File Content (first ~150 lines):\n\`\`\`${af.language || ''}\n${af.contentSnippet}\n\`\`\`\n`;
            }
        }

        // Build chat history section (last messages for continuity)
        let historySection = '';
        if (context && context.history && context.history.length > 0) {
            historySection = `\n## Recent Conversation:\n`;
            for (const msg of context.history.slice(-4)) {
                const role = msg.role || msg.type || 'user';
                const content = (msg.content || '').substring(0, 500);
                if (content.trim()) {
                    historySection += `**${role}:** ${content}\n`;
                }
            }
        }

        const systemPrompt = `You are Vigthoria AI, an expert coding assistant integrated into Vigthoria Coder IDE.
You have DIRECT ACCESS to the user's workspace files and can see their project structure.
Always analyze the ACTUAL workspace and files shown below — never fabricate or invent file contents.
If workspace context is provided, reference the real files and structure.
Mode: ${mode.toUpperCase()}
${workspaceSection}${activeFileSection}${historySection}`;

        const modeInstructions = {
            'ask': 'Provide helpful, accurate answers about the code and development. Reference actual files from the workspace when relevant.',
            'build': 'Generate code, create implementations, and provide development solutions. Use the workspace structure to understand the project.',
            'agent': 'Act as an autonomous coding agent. Analyze the workspace, identify issues, and provide actionable solutions with specific file references.',
            'operator': 'Provide operational analysis, deployment guidance, and infrastructure recommendations based on the actual project.',
            'developer': 'Provide expert developer assistance with deep code analysis.',
            'autonomous': 'Work autonomously to analyze, fix, and improve the codebase.',
        };

        const instruction = modeInstructions[mode] || modeInstructions['ask'];

        return `${systemPrompt}\n\n## Instructions\n${instruction}\n\n## User Request\n${message}`;
    }

    /**
     * Call Main API /api/ai-chat endpoint with SSE progress support
     * @param {string} message - User message
     * @param {object} context - Request context
     * @param {string} model - Preferred AI model
     * @param {string} mode - AI mode (ask, build, agent, operator)
     * @returns {Promise<{content, metadata, requestId}>}
     */
    async callMainAPI(message, context, model, mode, taskType) {
        const apiBaseUrl = this.apiUrl || CONFIG.server.modelRouterUrl || 'https://coder.vigthoria.io/api/model-router';
        const endpoint = `${apiBaseUrl}/route`;
        
        console.log(`[AI-SERVICE] 🚀 Calling Model Router: ${endpoint}`);
        console.log(`[AI-SERVICE] Mode: ${mode} | TaskType: ${taskType} | Model: ${model}`);

        // Build a context-rich prompt that includes workspace and file info
        let contextAwarePrompt;
        try {
            contextAwarePrompt = this.buildContextAwarePrompt(message, context, mode);
        } catch (promptErr) {
            console.warn('[AI-SERVICE] ⚠️ Context prompt build failed, using raw message:', promptErr.message);
            contextAwarePrompt = message;
        }

        // Build payload for Model Router /route endpoint
        const payload = {
            prompt: contextAwarePrompt,
            preferredModel: model,
            taskType: taskType || mode.toLowerCase(),
            service: 'smart',
            context: {
                mode: mode,
                hasCodeSelection: !!(context && context.activeFile),
                workspaceName: (context && context.workspace) ? context.workspace.name : undefined,
                projectType: (context && context.workspace) ? context.workspace.projectType : undefined,
                activeFile: (context && context.activeFile) ? context.activeFile.fileName : undefined,
                source: 'vigthoria-code-extension'
            },
            parameters: {
                temperature: 0.7,
                max_tokens: 4096,
                stream: false
            }
        };

        try {
            // Get authentication token (non-blocking)
            let authToken = null;
            try {
                authToken = await this.getAuthToken();
            } catch (authErr) {
                console.warn('[AI-SERVICE] ⚠️ Auth token retrieval failed:', authErr.message);
            }
            
            const headers = {
                'Content-Type': 'application/json',
                'X-VS-Extension-Auth': 'vigthoria-vscode-extension-key-2025'
            };
            
            if (authToken) {
                headers['Authorization'] = `Bearer ${authToken}`;
            }
            
            // AbortController with 35s timeout to prevent hanging
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 35000);
            
            // Make request to Model Router
            const response = await fetch(endpoint, {
                method: 'POST',
                headers: headers,
                body: JSON.stringify(payload),
                signal: controller.signal
            });
            
            clearTimeout(timeoutId);

            if (!response.ok) {
                const errorBody = await response.text().catch(() => 'No error body');
                throw new Error(`API ${response.status}: ${errorBody.substring(0, 200)}`);
            }

            let data;
            try {
                data = await response.json();
            } catch (parseErr) {
                const rawText = await response.text().catch(() => '');
                throw new Error(`Invalid JSON response: ${rawText.substring(0, 200)}`);
            }
            
            console.log(`[AI-SERVICE] ✅ Response received:`, {
                success: data.success,
                model: data.model,
                service: data.service
            });

            // Handle success: false from Model Router gracefully
            if (data.success === false && data.error) {
                console.warn(`[AI-SERVICE] ⚠️ Router returned error: ${data.error}`);
                // Still try to extract any response content
                if (!data.response && !data.content) {
                    throw new Error(`Model Router: ${data.error}`);
                }
            }

            // Extract response text from various possible fields
            let responseText = 'No response from AI';
            if (data.response) {
                responseText = data.response;
            } else if (data.content) {
                responseText = data.content;
            } else if (data.text) {
                responseText = data.text;
            }

            // Filter out tool calls from response
            responseText = this.filterToolCallsFromResponse(responseText);

            return {
                content: responseText,
                metadata: {
                    model: data.model || model,
                    mode: mode,
                    service: data.service || 'model-router',
                    processingTime: data.processingTime,
                    timestamp: data.timestamp || new Date().toISOString()
                },
                actions: []
            };

        } catch (error) {
            // Provide specific error context
            if (error.name === 'AbortError') {
                console.error(`[AI-SERVICE] ❌ Request timed out after 35s: ${endpoint}`);
                throw new Error('Request timed out (35s). The AI model may be loading. Please try again.');
            }
            console.error(`[AI-SERVICE] ❌ Main API call failed:`, error.message);
            throw error;
        }
    }

    // ── V3 Run History & Replay API ──────────────────────────────────

    async fetchRunHistory(limit = 20, offset = 0) {
        const headers = await this.getV3AgentHeaders();
        for (const baseUrl of this.getV3AgentBaseUrls()) {
            try {
                const url = `${baseUrl}/api/runs?limit=${encodeURIComponent(limit)}&offset=${encodeURIComponent(offset)}`;
                const res = await fetch(url, { headers, signal: AbortSignal.timeout(15000) });
                if (!res.ok) throw new Error(`${res.status}`);
                return await res.json();
            } catch (_) { /* try next */ }
        }
        throw new Error('All V3 endpoints unreachable for run history');
    }

    async fetchRunEvents(runId) {
        if (!runId || typeof runId !== 'string') throw new Error('Invalid runId');
        const headers = await this.getV3AgentHeaders();
        for (const baseUrl of this.getV3AgentBaseUrls()) {
            try {
                const url = `${baseUrl}/api/runs/${encodeURIComponent(runId)}/events`;
                const res = await fetch(url, { headers, signal: AbortSignal.timeout(15000) });
                if (!res.ok) throw new Error(`${res.status}`);
                return await res.json();
            } catch (_) { /* try next */ }
        }
        throw new Error('All V3 endpoints unreachable for run events');
    }

    async forkRun(runId, newRequest, eventIndex) {
        if (!runId || typeof runId !== 'string') throw new Error('Invalid runId');
        const headers = await this.getV3AgentHeaders();
        for (const baseUrl of this.getV3AgentBaseUrls()) {
            try {
                const url = `${baseUrl}/api/runs/${encodeURIComponent(runId)}/fork`;
                const res = await fetch(url, {
                    method: 'POST',
                    headers,
                    body: JSON.stringify({ request: newRequest, event_index: eventIndex }),
                    signal: AbortSignal.timeout(15000)
                });
                if (!res.ok) throw new Error(`${res.status}`);
                return await res.json();
            } catch (_) { /* try next */ }
        }
        throw new Error('All V3 endpoints unreachable for fork');
    }

    // ── SEAL Feedback Loop API ───────────────────────────────────────

    async fetchSEALScore(runId) {
        if (!runId || typeof runId !== 'string') throw new Error('Invalid runId');
        const headers = await this.getV3AgentHeaders();
        for (const baseUrl of this.getV3AgentBaseUrls()) {
            try {
                const url = `${baseUrl}/api/seal/score/${encodeURIComponent(runId)}`;
                const res = await fetch(url, { headers, signal: AbortSignal.timeout(15000) });
                if (!res.ok) throw new Error(`${res.status}`);
                return await res.json();
            } catch (_) { /* try next */ }
        }
        throw new Error('All V3 endpoints unreachable for SEAL score');
    }

    async submitSEALFeedback(runId, rating, comment) {
        if (!runId || typeof runId !== 'string') throw new Error('Invalid runId');
        const headers = await this.getV3AgentHeaders();
        for (const baseUrl of this.getV3AgentBaseUrls()) {
            try {
                const url = `${baseUrl}/api/seal/feedback`;
                const res = await fetch(url, {
                    method: 'POST',
                    headers,
                    body: JSON.stringify({ run_id: runId, rating, comment }),
                    signal: AbortSignal.timeout(15000)
                });
                if (!res.ok) throw new Error(`${res.status}`);
                return await res.json();
            } catch (_) { /* try next */ }
        }
        throw new Error('All V3 endpoints unreachable for SEAL feedback');
    }

    async fetchSEALTrend(limit = 20) {
        const headers = await this.getV3AgentHeaders();
        for (const baseUrl of this.getV3AgentBaseUrls()) {
            try {
                const url = `${baseUrl}/api/seal/trend?limit=${encodeURIComponent(limit)}`;
                const res = await fetch(url, { headers, signal: AbortSignal.timeout(15000) });
                if (!res.ok) throw new Error(`${res.status}`);
                return await res.json();
            } catch (_) { /* try next */ }
        }
        throw new Error('All V3 endpoints unreachable for SEAL trend');
    }

    // ── Deploy Project API ───────────────────────────────────────────

    async deployProjectToPreview(projectPath) {
        const headers = await this.getV3AgentHeaders();
        const request = `Deploy the project at ${projectPath} to a preview URL`;
        for (const baseUrl of this.getV3AgentBaseUrls()) {
            try {
                const url = `${baseUrl}/api/agent/run`;
                const res = await fetch(url, {
                    method: 'POST',
                    headers,
                    body: JSON.stringify({
                        request,
                        context: JSON.stringify({
                            workspace: projectPath,
                            workspacePath: projectPath,
                            projectPath,
                            targetPath: projectPath,
                            agentTaskType: 'deploy',
                            executionSurface: 'fork',
                            clientSurface: 'fork'
                        }),
                        stream: true
                    }),
                    signal: AbortSignal.timeout(120000)
                });
                if (!res.ok) throw new Error(`${res.status}`);
                const data = await this.collectV3AgentStream(res, { workspacePath: projectPath });
                return {
                    content: this.formatV3AgentResponse(data),
                    taskId: data.task_id || null,
                    backendUrl: baseUrl,
                    deployUrl: data.files ? Object.keys(data.files).find(k => /preview/i.test(k)) : null
                };
            } catch (_) { /* try next */ }
        }
        throw new Error('All V3 endpoints unreachable for deploy');
    }

    // ── Legion Parallel Orchestration API ────────────────────────────

    async legionSpawn(tasks) {
        if (!Array.isArray(tasks) || tasks.length === 0) throw new Error('Tasks array required');
        const headers = await this.getV3AgentHeaders();
        const legionUrl = process.env.VIGTHORIA_LEGION_URL || 'http://127.0.0.1:8020';
        const url = `${legionUrl}/api/legion/spawn`;
        const res = await fetch(url, {
            method: 'POST',
            headers,
            body: JSON.stringify({ tasks }),
            signal: AbortSignal.timeout(30000)
        });
        if (!res.ok) throw new Error(`Legion spawn failed: ${res.status}`);
        return await res.json();
    }

    async legionStatus(sessionId) {
        const headers = await this.getV3AgentHeaders();
        const legionUrl = process.env.VIGTHORIA_LEGION_URL || 'http://127.0.0.1:8020';
        const url = `${legionUrl}/api/legion/status/${encodeURIComponent(sessionId)}`;
        const res = await fetch(url, { headers, signal: AbortSignal.timeout(15000) });
        if (!res.ok) throw new Error(`Legion status failed: ${res.status}`);
        return await res.json();
    }

    async legionCollect(sessionId) {
        const headers = await this.getV3AgentHeaders();
        const legionUrl = process.env.VIGTHORIA_LEGION_URL || 'http://127.0.0.1:8020';
        const url = `${legionUrl}/api/legion/collect/${encodeURIComponent(sessionId)}`;
        const res = await fetch(url, { headers, signal: AbortSignal.timeout(60000) });
        if (!res.ok) throw new Error(`Legion collect failed: ${res.status}`);
        return await res.json();
    }

    /**
     * Filter out tool calls from AI response - these should be internal operations
     * Tool calls like {"tool": "read_file", ...} should not be shown to users
     */
    filterToolCallsFromResponse(text) {
        if (!text || typeof text !== 'string') return text;
        
        let filtered = text;
        
        // Remove JSON tool call blocks like {"tool": "read_file", ...}
        filtered = filtered.replace(/\{[\s\n]*"tool"[\s\n]*:[\s\S]*?\}\s*/g, '');
        filtered = filtered.replace(/```(?:json)?\s*\{[\s\S]*?"tool"[\s\S]*?\}\s*```/gmi, '');
        
        // Remove markdown formatted tool calls like "- **Tool:** read_file"
        filtered = filtered.replace(/^\s*-?\s*\*?\*?Tool\*?\*?:?\s*[a-z_]+.*$/gmi, '');
        
        // Remove "## Parameters" sections that follow tool calls
        filtered = filtered.replace(/^##\s*Parameters\s*[\s\S]*?(?=^##|\n\n\n|$)/gmi, '');
        
        // Remove lines like "- **Path:** /some/path" that are tool call parameters
        filtered = filtered.replace(/^\s*-\s*\*\*Path\*\*:\s*\/.*$/gmi, '');
        filtered = filtered.replace(/^\s*-\s*\*\*File\*\*:\s*\/.*$/gmi, '');
        filtered = filtered.replace(/^\s*-\s*\*\*(?:Args?|Parameters?)\*\*:\s*.*$/gmi, '');
        
        // Remove MCP tool call syntax [tool_name params]
        filtered = filtered.replace(/\[(?:read_file|write_file|list_dir|search|grep)\s+[^\]]+\]/gi, '');
        
        // Remove "I'll use the X tool" or "Using the X tool" phrases
        filtered = filtered.replace(/^.*(?:I'll use|Using|Let me use|I will use)\s+(?:the\s+)?[a-z_]+\s+tool.*$/gmi, '');
        filtered = filtered.replace(/^\s*(?:⚙️?\s*)?(?:Executing|Running|Calling|Invoking):\s*.*$/gmi, '');
        filtered = filtered.replace(/^\s*(?:Allow|Approve)\??\s*\[[^\]]*\]\s*$/gmi, '');
        filtered = filtered.replace(/^Would you like me to:[\s\S]*?(?=\n\n|$)/gmi, '');
        filtered = filtered.replace(/^I can help by:[\s\S]*?(?=\n\n|$)/gmi, '');
        
        // Clean up excessive newlines
        filtered = filtered.replace(/\n{3,}/g, '\n\n');
        
        return filtered.trim();
    }
}

module.exports = { AIService, VigthoriaChatInterface: AIService };

