const vscode = require('vscode');
const fs = require('fs');
const path = require('path');

/**
 * Vigthoria Mode Utilities
 * Shared functionality for all modes - inspired by Cursor, Windsurf, and Copilot
 * 
 * Features:
 * - @ mentions parsing (@file, @folder, @workspace)
 * - File/folder content reading
 * - Streaming progress updates
 * - Code block extraction
 * - Diff generation
 * - Apply changes to files
 */
class ModeUtils {
    constructor(webviewProvider = null) {
        this.webviewProvider = webviewProvider;
        this.pendingChanges = new Map();
        this.changeHistory = [];
    }

    setWebviewProvider(provider) {
        this.webviewProvider = provider;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // @ MENTIONS PARSING - Like Cursor/Copilot @file, @folder mentions
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Parse @ mentions from message and resolve them to actual content
     * Supports: @file:path, @folder:path, @workspace, @selection
     */
    async parseAtMentions(message, workspacePath) {
        const mentions = {
            files: [],
            folders: [],
            workspace: false,
            selection: null,
            cleanMessage: message
        };

        // Parse @file:filename or @file filename
        const fileMatches = message.matchAll(/@file[:\s]+([^\s@]+)/gi);
        for (const match of fileMatches) {
            const filePath = this.resolveFilePath(match[1], workspacePath);
            if (filePath && fs.existsSync(filePath)) {
                const content = await this.readFileContent(filePath);
                mentions.files.push({
                    path: filePath,
                    name: path.basename(filePath),
                    content: content,
                    language: this.getLanguageFromExt(filePath)
                });
            }
            mentions.cleanMessage = mentions.cleanMessage.replace(match[0], '').trim();
        }

        // Parse @folder:foldername or @folder foldername
        const folderMatches = message.matchAll(/@folder[:\s]+([^\s@]+)/gi);
        for (const match of folderMatches) {
            const folderPath = this.resolveFilePath(match[1], workspacePath);
            if (folderPath && fs.existsSync(folderPath)) {
                const contents = await this.readFolderContents(folderPath, workspacePath);
                mentions.folders.push({
                    path: folderPath,
                    name: path.basename(folderPath),
                    ...contents
                });
            }
            mentions.cleanMessage = mentions.cleanMessage.replace(match[0], '').trim();
        }

        // Parse @workspace
        if (/@workspace\b/i.test(message)) {
            mentions.workspace = true;
            mentions.cleanMessage = mentions.cleanMessage.replace(/@workspace/gi, '').trim();
        }

        // Parse @selection
        if (/@selection\b/i.test(message)) {
            mentions.selection = await this.getActiveSelection();
            mentions.cleanMessage = mentions.cleanMessage.replace(/@selection/gi, '').trim();
        }

        return mentions;
    }

    /**
     * Smart file/folder detection from message (without @ prefix)
     * Scans workspace to find matching names
     */
    async detectFilesAndFolders(message, workspacePath) {
        const detected = {
            files: [],
            folders: []
        };

        try {
            const items = fs.readdirSync(workspacePath, { withFileTypes: true });
            const lowerMessage = message.toLowerCase();

            for (const item of items) {
                if (item.name.startsWith('.')) continue;
                
                const lowerName = item.name.toLowerCase();
                // Check if folder/file name appears in message
                if (lowerMessage.includes(lowerName)) {
                    const fullPath = path.join(workspacePath, item.name);
                    
                    if (item.isDirectory()) {
                        const contents = await this.readFolderContents(fullPath, workspacePath);
                        detected.folders.push({
                            path: fullPath,
                            name: item.name,
                            ...contents
                        });
                    } else {
                        const content = await this.readFileContent(fullPath);
                        detected.files.push({
                            path: fullPath,
                            name: item.name,
                            content: content,
                            language: this.getLanguageFromExt(fullPath)
                        });
                    }
                }
            }
        } catch (error) {
            console.warn('Error scanning workspace:', error.message);
        }

        return detected;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // FILE CONTENT READING
    // ═══════════════════════════════════════════════════════════════════════════

    resolveFilePath(pathStr, workspacePath) {
        if (path.isAbsolute(pathStr)) {
            return pathStr;
        }
        return path.join(workspacePath, pathStr);
    }

    async readFileContent(filePath, maxSize = 50000) {
        try {
            const stats = fs.statSync(filePath);
            if (stats.size > maxSize) {
                const content = fs.readFileSync(filePath, 'utf-8');
                return content.substring(0, maxSize) + `\n\n... [Truncated - file is ${(stats.size / 1024).toFixed(1)}KB]`;
            }
            return fs.readFileSync(filePath, 'utf-8');
        } catch (error) {
            return `[Error reading file: ${error.message}]`;
        }
    }

    async readFolderContents(folderPath, workspacePath, maxFiles = 20) {
        const result = {
            fileList: [],
            fileContents: [],
            summary: ''
        };

        try {
            const items = fs.readdirSync(folderPath, { withFileTypes: true });
            const codeExts = ['.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.go', '.rs', '.c', '.cpp', '.h', '.html', '.css', '.json', '.md', '.yaml', '.yml'];
            
            let fileCount = 0;
            for (const item of items) {
                if (item.name.startsWith('.')) continue;
                
                const itemPath = path.join(folderPath, item.name);
                const relativePath = path.relative(workspacePath, itemPath);
                
                if (item.isDirectory()) {
                    result.fileList.push({ type: 'folder', name: item.name, path: relativePath });
                } else {
                    result.fileList.push({ type: 'file', name: item.name, path: relativePath });
                    
                    // Read code file contents
                    const ext = path.extname(item.name).toLowerCase();
                    if (codeExts.includes(ext) && fileCount < maxFiles) {
                        try {
                            const stats = fs.statSync(itemPath);
                            if (stats.size < 30000) { // 30KB max per file
                                const content = fs.readFileSync(itemPath, 'utf-8');
                                result.fileContents.push({
                                    name: item.name,
                                    path: relativePath,
                                    language: ext.slice(1),
                                    content: content,
                                    size: stats.size
                                });
                                fileCount++;
                            }
                        } catch (e) { /* ignore */ }
                    }
                }
            }

            result.summary = `${result.fileList.filter(f => f.type === 'folder').length} folders, ${result.fileList.filter(f => f.type === 'file').length} files`;
        } catch (error) {
            result.summary = `Error: ${error.message}`;
        }

        return result;
    }

    async getActiveSelection() {
        try {
            const editor = vscode.window.activeTextEditor;
            if (!editor) return null;

            const selection = editor.selection;
            if (selection.isEmpty) return null;

            return {
                text: editor.document.getText(selection),
                fileName: path.basename(editor.document.fileName),
                filePath: editor.document.fileName,
                language: editor.document.languageId,
                startLine: selection.start.line + 1,
                endLine: selection.end.line + 1
            };
        } catch (error) {
            return null;
        }
    }

    async getActiveFileContext() {
        try {
            const editor = vscode.window.activeTextEditor;
            if (!editor) return null;

            const doc = editor.document;
            return {
                fileName: path.basename(doc.fileName),
                filePath: doc.fileName,
                language: doc.languageId,
                content: doc.getText(),
                lineCount: doc.lineCount,
                cursorLine: editor.selection.active.line + 1
            };
        } catch (error) {
            return null;
        }
    }

    getLanguageFromExt(filePath) {
        const ext = path.extname(filePath).toLowerCase();
        const langMap = {
            '.js': 'javascript', '.jsx': 'javascript',
            '.ts': 'typescript', '.tsx': 'typescript',
            '.py': 'python',
            '.java': 'java',
            '.go': 'go',
            '.rs': 'rust',
            '.c': 'c', '.cpp': 'cpp', '.h': 'c',
            '.html': 'html',
            '.css': 'css', '.scss': 'scss',
            '.json': 'json',
            '.md': 'markdown',
            '.yaml': 'yaml', '.yml': 'yaml',
            '.sql': 'sql',
            '.sh': 'bash',
            '.rb': 'ruby',
            '.php': 'php'
        };
        return langMap[ext] || 'text';
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // STREAMING & PROGRESS - Like Windsurf's thinking process
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Send streaming thought/progress to webview
     */
    streamThought(thought, type = 'thinking') {
        if (!this.webviewProvider || !this.webviewProvider._view) return;
        
        try {
            this.webviewProvider._view.webview.postMessage({
                type: 'streamThought',
                data: {
                    thought: thought,
                    type: type, // 'thinking', 'reading', 'writing', 'analyzing', 'complete'
                    timestamp: new Date().toISOString()
                }
            });
        } catch (error) {
            console.warn('Could not stream thought:', error.message);
        }
    }

    /**
     * Send file read progress
     */
    streamFileRead(fileName, size) {
        this.streamThought(`📖 Reading: ${fileName} (${this.formatSize(size)})`, 'reading');
    }

    /**
     * Send analysis progress
     */
    streamAnalysis(step) {
        this.streamThought(`🔍 ${step}`, 'analyzing');
    }

    /**
     * Send code generation progress
     */
    streamGeneration(step) {
        this.streamThought(`⚡ ${step}`, 'generating');
    }

    formatSize(bytes) {
        if (bytes < 1024) return `${bytes}B`;
        if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
        return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // CODE BLOCK EXTRACTION & APPLY CHANGES
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Extract code blocks from AI response
     * Supports multiple formats for file creation
     */
    extractCodeBlocks(response) {
        const blocks = [];
        
        // Format 1: --- FILE: path --- content --- END FILE ---
        const fileBlockRegex = /---\s*FILE:\s*([^\n-]+)\s*---\n([\s\S]*?)---\s*END\s*FILE\s*---/gi;
        let match;
        while ((match = fileBlockRegex.exec(response)) !== null) {
            blocks.push({
                type: 'file',
                path: match[1].trim(),
                content: match[2].trim(),
                format: 'vigthoria'
            });
        }

        // Format 2: ```language:filename content ```
        const fencedWithPath = /```(\w+):([^\n]+)\n([\s\S]*?)```/gi;
        while ((match = fencedWithPath.exec(response)) !== null) {
            blocks.push({
                type: 'file',
                path: match[2].trim(),
                content: match[3].trim(),
                language: match[1],
                format: 'cursor-style'
            });
        }

        // Format 3: Standard ```language content ``` (for inline suggestions)
        const fencedStandard = /```(\w*)\n([\s\S]*?)```/gi;
        while ((match = fencedStandard.exec(response)) !== null) {
            // Skip if already captured by other formats
            const content = match[2].trim();
            if (!blocks.some(b => b.content === content)) {
                blocks.push({
                    type: 'code',
                    content: content,
                    language: match[1] || 'text',
                    format: 'standard'
                });
            }
        }

        return blocks;
    }

    /**
     * Apply file changes to workspace
     * Returns summary of what was changed
     */
    async applyFileChanges(fileBlocks, workspacePath) {
        const results = {
            created: [],
            modified: [],
            errors: []
        };

        for (const block of fileBlocks) {
            if (block.type !== 'file' || !block.path) continue;

            try {
                const fullPath = this.resolveFilePath(block.path, workspacePath);
                const dir = path.dirname(fullPath);

                // Create directory if needed
                if (!fs.existsSync(dir)) {
                    fs.mkdirSync(dir, { recursive: true });
                }

                const exists = fs.existsSync(fullPath);
                
                // Save current content for undo
                if (exists) {
                    const oldContent = fs.readFileSync(fullPath, 'utf-8');
                    this.changeHistory.push({
                        type: 'modify',
                        path: fullPath,
                        oldContent: oldContent,
                        newContent: block.content,
                        timestamp: new Date().toISOString()
                    });
                } else {
                    this.changeHistory.push({
                        type: 'create',
                        path: fullPath,
                        content: block.content,
                        timestamp: new Date().toISOString()
                    });
                }

                // Write file
                fs.writeFileSync(fullPath, block.content, 'utf-8');

                if (exists) {
                    results.modified.push(block.path);
                } else {
                    results.created.push(block.path);
                }

                this.streamThought(`✅ ${exists ? 'Modified' : 'Created'}: ${block.path}`, 'writing');

            } catch (error) {
                results.errors.push({ path: block.path, error: error.message });
                this.streamThought(`❌ Failed: ${block.path} - ${error.message}`, 'error');
            }
        }

        return results;
    }

    /**
     * Undo last change
     */
    async undoLastChange() {
        if (this.changeHistory.length === 0) {
            return { success: false, message: 'No changes to undo' };
        }

        const lastChange = this.changeHistory.pop();

        try {
            if (lastChange.type === 'modify') {
                fs.writeFileSync(lastChange.path, lastChange.oldContent, 'utf-8');
                return { success: true, message: `Restored: ${path.basename(lastChange.path)}` };
            } else if (lastChange.type === 'create') {
                fs.unlinkSync(lastChange.path);
                return { success: true, message: `Deleted: ${path.basename(lastChange.path)}` };
            }
        } catch (error) {
            return { success: false, message: `Undo failed: ${error.message}` };
        }

        return { success: false, message: 'Unknown change type' };
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // CONTEXT BUILDING FOR AI
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Build comprehensive context for AI from mentions, files, and history
     */
    buildAIContext(options = {}) {
        let context = '';

        // Add mentioned files
        if (options.files && options.files.length > 0) {
            context += '\n\n## 📁 Referenced Files:\n';
            for (const file of options.files) {
                context += `\n### ${file.name}\n`;
                context += `\`\`\`${file.language}\n${file.content}\n\`\`\`\n`;
            }
        }

        // Add mentioned folders
        if (options.folders && options.folders.length > 0) {
            for (const folder of options.folders) {
                context += `\n\n## 📂 Folder: ${folder.name}\n`;
                context += `**Contents:** ${folder.summary}\n\n`;
                
                for (const file of folder.fileContents || []) {
                    context += `### ${file.name}\n`;
                    context += `\`\`\`${file.language}\n${file.content}\n\`\`\`\n\n`;
                }
            }
        }

        // Add selection
        if (options.selection) {
            context += `\n\n## ✨ Selected Code (${options.selection.fileName}, lines ${options.selection.startLine}-${options.selection.endLine}):\n`;
            context += `\`\`\`${options.selection.language}\n${options.selection.text}\n\`\`\`\n`;
        }

        // Add active file
        if (options.activeFile) {
            context += `\n\n## 📄 Current File: ${options.activeFile.fileName}\n`;
            context += `\`\`\`${options.activeFile.language}\n${options.activeFile.content}\n\`\`\`\n`;
        }

        // Add conversation history
        if (options.history && options.history.length > 0) {
            context += '\n\n## 💬 Previous Conversation:\n';
            for (const msg of options.history) {
                const role = msg.type === 'user' ? 'User' : 'AI';
                const content = msg.content || '';
                if (content) {
                    context += `**${role}:** ${content.substring(0, 400)}${content.length > 400 ? '...' : ''}\n\n`;
                }
            }
        }

        return context;
    }

    /**
     * Format AI response with actionable buttons
     */
    formatResponseWithActions(response, options = {}) {
        let formatted = response;

        // Add apply button for file changes
        if (options.hasFileChanges) {
            formatted += '\n\n---\n';
            formatted += '**Actions:** ';
            formatted += '[Apply Changes] [Preview Diff] [Copy Code]';
        }

        return formatted;
    }
}

// ═══════════════════════════════════════════════════════════════════════════
// QUICK ACTIONS - Like Copilot's inline actions
// ═══════════════════════════════════════════════════════════════════════════

const QUICK_ACTIONS = {
    explain: {
        name: 'Explain',
        icon: '💡',
        prompt: (code, language) => `Explain this ${language} code in detail:\n\n\`\`\`${language}\n${code}\n\`\`\`\n\nProvide:\n1. What the code does\n2. How it works step by step\n3. Any important patterns or techniques used\n4. Potential improvements or issues`
    },
    fix: {
        name: 'Fix',
        icon: '🔧',
        prompt: (code, language, error = '') => `Fix any issues in this ${language} code:\n\n\`\`\`${language}\n${code}\n\`\`\`\n${error ? `\nError: ${error}\n` : ''}\nProvide:\n1. Identify the issue(s)\n2. Explain why it's a problem\n3. Provide the corrected code\n4. Explain the fix`
    },
    optimize: {
        name: 'Optimize',
        icon: '⚡',
        prompt: (code, language) => `Optimize this ${language} code for better performance and readability:\n\n\`\`\`${language}\n${code}\n\`\`\`\n\nProvide:\n1. Identify optimization opportunities\n2. Show the optimized code\n3. Explain the improvements\n4. Benchmark comparison if applicable`
    },
    document: {
        name: 'Document',
        icon: '📝',
        prompt: (code, language) => `Add comprehensive documentation to this ${language} code:\n\n\`\`\`${language}\n${code}\n\`\`\`\n\nProvide:\n1. JSDoc/docstrings for all functions\n2. Inline comments for complex logic\n3. Usage examples\n4. Parameter and return type descriptions`
    },
    test: {
        name: 'Generate Tests',
        icon: '🧪',
        prompt: (code, language) => `Generate comprehensive unit tests for this ${language} code:\n\n\`\`\`${language}\n${code}\n\`\`\`\n\nProvide:\n1. Tests for all functions/methods\n2. Edge cases and error handling\n3. Mocking if needed\n4. Use appropriate testing framework`
    },
    refactor: {
        name: 'Refactor',
        icon: '♻️',
        prompt: (code, language) => `Refactor this ${language} code following SOLID principles and clean code practices:\n\n\`\`\`${language}\n${code}\n\`\`\`\n\nProvide:\n1. Identify code smells\n2. Apply appropriate design patterns\n3. Show the refactored code\n4. Explain the improvements`
    },
    convert: {
        name: 'Convert',
        icon: '🔄',
        prompt: (code, fromLang, toLang) => `Convert this ${fromLang} code to ${toLang}:\n\n\`\`\`${fromLang}\n${code}\n\`\`\`\n\nProvide:\n1. Idiomatic ${toLang} code\n2. Handle language-specific differences\n3. Maintain functionality\n4. Add appropriate error handling`
    }
};

module.exports = { ModeUtils, QUICK_ACTIONS };
