/**
 * GitHub Code Viewer - Main JavaScript
 */

(function($) {
    'use strict';
    
    // GitHub Code Viewer Class
    class GitHubCodeViewer {
        constructor(element) {
            this.$element = $(element);
            this.repo = this.$element.data('repo');
            this.theme = this.$element.data('theme');
            this.showLineNumbers = this.$element.data('show-line-numbers');
            this.initialFile = this.$element.data('initial-file');
            
            this.files = [];
            this.openTabs = [];
            this.activeTab = null;
            this.fileCache = {};
            this.activeRequests = []; // Track active AJAX requests
            this.currentPath = ''; // Track current folder path
            
            this.init();
        }
        
        init() {
            this.bindEvents();
            this.loadRepositoryFiles();
        }
        
        bindEvents() {
            // Search functionality with debouncing
            let searchTimeout;
            this.$element.on('input', '.mcb-search-input', (e) => {
                clearTimeout(searchTimeout);
                searchTimeout = setTimeout(() => {
                    this.filterFiles($(e.target).val());
                }, 300); // Debounce for 300ms
            });
            
            // File/folder selection
            this.$element.on('click', '.mcb-file-item', (e) => {
                const $item = $(e.currentTarget);
                const isFolder = $item.data('is-folder');
                const path = $item.data('path');
                
                if (isFolder) {
                    // Navigate to folder
                    this.loadRepositoryFiles(path);
                } else {
                    // Load file
                    this.loadFile(path);
                }
            });
            
            // Tab management
            this.$element.on('click', '.mcb-tab', (e) => {
                const $tab = $(e.currentTarget);
                const filePath = $tab.data('path');
                this.switchToTab(filePath);
            });
            
            this.$element.on('click', '.mcb-tab-close', (e) => {
                e.stopPropagation();
                const $tab = $(e.target).closest('.mcb-tab');
                const filePath = $tab.data('path');
                this.closeTab(filePath);
            });
            
            // Copy button
            this.$element.on('click', '.mcb-copy-btn', (e) => {
                this.copyCode($(e.target));
            });
            
            // Home button - go to root
            this.$element.on('click', '.mcb-home-btn', () => {
                this.loadRepositoryFiles(''); // Load root
            });
            
            // Refresh button
            this.$element.on('click', '.mcb-refresh-btn', () => {
                this.refreshFiles();
            });
            
            // Fullscreen toggle
            this.$element.on('click', '.mcb-fullscreen-btn', () => {
                this.toggleFullscreen();
            });
        }
        
        loadRepositoryFiles(path = '') {
            console.log('MCB: Loading repository files for:', this.repo, 'path:', path);
            const $fileList = this.$element.find('.mcb-file-list');
            
            // Update current path
            this.currentPath = path;
            
            // Show loading indicator
            $fileList.html('<div class="mcb-loading"><div class="mcb-spinner"></div><span>Loading files...</span></div>');
            
            // Abort any pending requests
            this.abortActiveRequests();
            
            console.log('MCB: Making AJAX request to:', mcb_ajax.ajax_url);
            const request = $.ajax({
                url: mcb_ajax.ajax_url,
                type: 'POST',
                data: {
                    action: 'mcb_get_repo_files',
                    repo: this.repo,
                    path: path,
                    nonce: mcb_ajax.nonce
                },
                success: (response) => {
                    console.log('MCB: AJAX response:', response);
                    this.removeRequest(request);
                    if (response.success) {
                        console.log('MCB: Files loaded:', response.data);
                        this.files = response.data;
                        this.renderFileList();
                        
                        // Load initial file if specified
                        if (this.initialFile) {
                            const file = this.files.find(f => f.path === this.initialFile);
                            if (file) {
                                this.loadFile(this.initialFile);
                            }
                        }
                    } else {
                        console.error('MCB: Error:', response.data);
                        $fileList.html('<div class="mcb-error">' + response.data + '</div>');
                    }
                },
                error: (xhr, status, error) => {
                    console.error('MCB: AJAX failed:', status, error);
                    this.removeRequest(request);
                    $fileList.html('<div class="mcb-error">Failed to load repository files: ' + error + '</div>');
                }
            });
            
            this.activeRequests.push(request);
        }
        
        renderFileList() {
            const $fileList = this.$element.find('.mcb-file-list');
            $fileList.empty();
            
            // Add current path breadcrumb if not at root
            if (this.currentPath) {
                const $breadcrumb = $('<div class="mcb-breadcrumb">');
                $breadcrumb.append('<span class="mcb-path-label">Path: </span>');
                $breadcrumb.append('<span class="mcb-current-path">/' + this.escapeHtml(this.currentPath) + '</span>');
                $fileList.append($breadcrumb);
            }
            
            // Render files and folders
            this.files.forEach(file => {
                const $item = $('<div class="mcb-file-item">')
                    .attr('data-path', file.path)
                    .attr('data-name', file.name.toLowerCase())
                    .attr('data-is-folder', file.is_folder || false);
                
                // Add appropriate icon
                let icon;
                if (file.type === 'parent') {
                    icon = '⬆'; // Up arrow for parent
                    $item.addClass('mcb-parent-folder');
                } else if (file.is_folder) {
                    icon = '📁'; // Folder icon
                    $item.addClass('mcb-folder');
                } else {
                    icon = this.getFileIcon(file.type);
                    $item.addClass('mcb-file');
                }
                
                $item.append('<span class="mcb-file-icon">' + icon + '</span>');
                $item.append('<span class="mcb-file-name">' + this.escapeHtml(file.name) + '</span>');
                
                // Add file size for files only
                if (!file.is_folder) {
                    const sizeStr = this.formatFileSize(file.size);
                    $item.append('<span class="mcb-file-size">' + sizeStr + '</span>');
                }
                
                $fileList.append($item);
            });
        }
        
        organizeFileTree(files) {
            const tree = {};
            files.forEach(file => {
                const parts = file.path.split('/');
                let current = tree;
                
                parts.forEach((part, index) => {
                    if (index === parts.length - 1) {
                        // It's a file
                        current[part] = file;
                    } else {
                        // It's a directory
                        if (!current[part]) {
                            current[part] = {};
                        }
                        current = current[part];
                    }
                });
            });
            return tree;
        }
        
        filterFiles(searchTerm) {
            const $items = this.$element.find('.mcb-file-item');
            const term = searchTerm.toLowerCase();
            
            $items.each((index, item) => {
                const $item = $(item);
                const fileName = $item.data('name');
                
                if (!term || fileName.includes(term)) {
                    $item.show();
                } else {
                    $item.hide();
                }
            });
        }
        
        loadFile(filePath) {
            // Limit cache size to prevent memory issues
            this.limitCacheSize();
            
            // Check if file is already in cache
            if (this.fileCache[filePath]) {
                this.displayFile(filePath, this.fileCache[filePath]);
                return;
            }
            
            // Update status
            this.updateStatus('Loading file...');
            
            const request = $.ajax({
                url: mcb_ajax.ajax_url,
                type: 'POST',
                data: {
                    action: 'mcb_load_file',
                    repo: this.repo,
                    file_path: filePath,
                    nonce: mcb_ajax.nonce
                },
                success: (response) => {
                    this.removeRequest(request);
                    if (response.success) {
                        this.fileCache[filePath] = response.data;
                        this.displayFile(filePath, response.data);
                        this.updateStatus('Ready');
                    } else {
                        this.showError('Failed to load file: ' + response.data);
                        this.updateStatus('Error loading file');
                    }
                },
                error: () => {
                    this.removeRequest(request);
                    this.showError('Network error while loading file');
                    this.updateStatus('Network error');
                }
            });
            
            this.activeRequests.push(request);
        }
        
        displayFile(filePath, fileData) {
            // Store in cache
            this.fileCache[filePath] = fileData;
            
            // Limit number of open tabs to prevent memory issues
            const maxTabs = 10;
            
            // Add to tabs if not already open
            if (!this.openTabs.includes(filePath)) {
                // Check tab limit
                if (this.openTabs.length >= maxTabs) {
                    // Close the oldest tab
                    const oldestTab = this.openTabs[0];
                    this.closeTab(oldestTab);
                }
                
                this.openTabs.push(filePath);
                this.addTab(filePath, fileData.filename);
            }
            
            // Only switch to tab if not already active
            if (this.activeTab !== filePath) {
                this.switchToTab(filePath);
            } else {
                // Just update the content if already active
                const $codeArea = this.$element.find('.mcb-code-area');
                const safeContent = this.createSafeCodeDisplay(fileData.content, fileData.filename);
                $codeArea.html(safeContent);
                
                // Apply syntax highlighting
                if (typeof Prism !== 'undefined') {
                    Prism.highlightAll();
                }
                
                // Update status
                const fileSize = this.formatFileSize(fileData.content.length);
                const lineCount = fileData.content.split('\n').length;
                this.$element.find('.mcb-file-info').text(fileData.filename + ' • ' + lineCount + ' lines • ' + fileSize);
            }
            
            // Display content
            const $codeArea = this.$element.find('.mcb-code-area');
            
            // Create safe HTML content
            const safeContent = this.createSafeCodeDisplay(fileData.content, fileData.filename);
            $codeArea.html(safeContent);
            
            // Apply syntax highlighting if Prism is loaded
            if (typeof Prism !== 'undefined') {
                Prism.highlightAll();
            }
            
            // Mark file as active in sidebar
            this.$element.find('.mcb-file-item').removeClass('active');
            this.$element.find('.mcb-file-item[data-path="' + filePath + '"]').addClass('active');
            
            // Update file info
            const file = this.files.find(f => f.path === filePath);
            if (file) {
                this.updateFileInfo(file);
            }
        }
        
        createSafeCodeDisplay(content, filename) {
            // The content is already escaped by PHP, but we'll double-check
            const $container = $('<div class="mcb-code-container">');
            
            // Header
            const $header = $('<div class="mcb-code-header">');
            $header.append($('<span class="mcb-filename">').text(filename));
            
            // Copy button - store content in data, not attribute
            const $copyBtn = $('<button class="mcb-copy-btn">Copy</button>');
            $copyBtn.data('content', content); // Use data() instead of attr()
            $header.append($copyBtn);
            
            $container.append($header);
            
            // Code wrapper
            const $wrapper = $('<div class="mcb-code-wrapper">');
            const language = this.detectLanguage(filename);
            
            // Create pre/code structure
            const $pre = $('<pre>').addClass('line-numbers');
            const $code = $('<code>').addClass('language-' + language);
            
            // CRITICAL: Ensure content is text, not HTML
            $code.text(content);
            
            $pre.append($code);
            $wrapper.append($pre);
            $container.append($wrapper);
            
            return $container;
        }
        
        addTab(filePath, filename) {
            const $tabs = this.$element.find('.mcb-tabs');
            
            const $tab = $('<div class="mcb-tab">')
                .attr('data-path', filePath);
            
            $tab.append('<span class="mcb-tab-title">' + this.escapeHtml(filename) + '</span>');
            $tab.append('<span class="mcb-tab-close">×</span>');
            
            $tabs.append($tab);
        }
        
        switchToTab(filePath) {
            // Prevent switching if already active
            if (this.activeTab === filePath) {
                return;
            }
            
            this.activeTab = filePath;
            
            // Update tab states
            this.$element.find('.mcb-tab').removeClass('active');
            this.$element.find('.mcb-tab[data-path="' + filePath + '"]').addClass('active');
            
            // Load file content if cached, otherwise just display the tab
            if (this.fileCache[filePath]) {
                // Display cached content without calling displayFile
                const $codeArea = this.$element.find('.mcb-code-area');
                const fileData = this.fileCache[filePath];
                const safeContent = this.createSafeCodeDisplay(fileData.content, fileData.filename);
                $codeArea.html(safeContent);
                
                // Apply syntax highlighting if Prism is loaded
                if (typeof Prism !== 'undefined') {
                    Prism.highlightAll();
                }
                
                // Update status
                const fileSize = this.formatFileSize(fileData.content.length);
                const lineCount = fileData.content.split('\n').length;
                this.$element.find('.mcb-file-info').text(fileData.filename + ' • ' + lineCount + ' lines • ' + fileSize);
            }
        }
        
        closeTab(filePath) {
            // Remove from open tabs
            const index = this.openTabs.indexOf(filePath);
            if (index > -1) {
                this.openTabs.splice(index, 1);
            }
            
            // Remove tab element
            this.$element.find('.mcb-tab[data-path="' + filePath + '"]').remove();
            
            // If this was the active tab, switch to another
            if (this.activeTab === filePath) {
                if (this.openTabs.length > 0) {
                    this.switchToTab(this.openTabs[this.openTabs.length - 1]);
                } else {
                    // Show welcome screen
                    this.showWelcome();
                }
            }
        }
        
        copyCode($button) {
            const content = $button.data('content'); // Use data() instead of attr()
            
            if (!content) {
                return;
            }
            
            // Create temporary textarea
            const $temp = $('<textarea>');
            $temp.val(content);
            $('body').append($temp);
            $temp.select();
            
            try {
                document.execCommand('copy');
                $button.text('Copied!').addClass('copied');
                setTimeout(() => {
                    $button.text('Copy').removeClass('copied');
                }, 2000);
            } catch (err) {
                console.error('Failed to copy:', err);
            }
            
            $temp.remove();
        }
        
        refreshFiles() {
            // Abort any pending requests first
            this.abortActiveRequests();
            
            // Clear cache
            this.fileCache = {};
            
            // Reload files at current path
            this.loadRepositoryFiles(this.currentPath);
            this.updateStatus('Repository refreshed');
        }
        
        toggleFullscreen() {
            this.$element.toggleClass('fullscreen');
        }
        
        showWelcome() {
            const $codeArea = this.$element.find('.mcb-code-area');
            const welcome = `
                <div class="mcb-welcome">
                    <svg viewBox="0 0 24 24" width="64" height="64">
                        <path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/>
                    </svg>
                    <h4>GitHub Code Viewer</h4>
                    <p>Select a file from the sidebar to view its content</p>
                </div>
            `;
            $codeArea.html(welcome);
        }
        
        showError(message) {
            const $codeArea = this.$element.find('.mcb-code-area');
            $codeArea.html('<div class="mcb-error">' + this.escapeHtml(message) + '</div>');
        }
        
        updateStatus(text) {
            this.$element.find('.mcb-status-text').text(text);
        }
        
        updateFileInfo(file) {
            const info = file.name + ' • ' + this.formatFileSize(file.size) + ' • ' + file.type;
            this.$element.find('.mcb-file-info').text(info);
        }
        
        formatFileSize(bytes) {
            if (bytes === 0) return '0 B';
            const k = 1024;
            const sizes = ['B', 'KB', 'MB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
        }
        
        detectLanguage(filename) {
            const ext = filename.split('.').pop().toLowerCase();
            const languageMap = {
                'js': 'javascript',
                'jsx': 'jsx',
                'ts': 'typescript',
                'tsx': 'tsx',
                'py': 'python',
                'rb': 'ruby',
                'php': 'php',
                'java': 'java',
                'c': 'c',
                'cpp': 'cpp',
                'cs': 'csharp',
                'go': 'go',
                'rs': 'rust',
                'swift': 'swift',
                'kt': 'kotlin',
                'scala': 'scala',
                'r': 'r',
                'sql': 'sql',
                'sh': 'bash',
                'yml': 'yaml',
                'json': 'json',
                'xml': 'xml',
                'html': 'html',
                'css': 'css',
                'scss': 'scss',
                'md': 'markdown'
            };
            
            return languageMap[ext] || 'plain';
        }
        
        getFileIcon(type) {
            const icons = {
                'javascript': '📜',
                'python': '🐍',
                'php': '🐘',
                'java': '☕',
                'cpp': '⚙️',
                'go': '🐹',
                'rust': '🦀',
                'ruby': '💎',
                'html': '🌐',
                'css': '🎨',
                'json': '📋',
                'markdown': '📝',
                'default': '📄'
            };
            
            return icons[type] || icons.default;
        }
        
        escapeHtml(text) {
            const map = {
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#039;'
            };
            
            return text.replace(/[&<>"']/g, m => map[m]);
        }
        
        limitCacheSize() {
            // Limit cache to 20 files to prevent memory issues
            const maxCacheSize = 20;
            const cacheKeys = Object.keys(this.fileCache);
            
            if (cacheKeys.length >= maxCacheSize) {
                // Remove oldest cached files (FIFO)
                const toRemove = cacheKeys.slice(0, cacheKeys.length - maxCacheSize + 1);
                toRemove.forEach(key => {
                    delete this.fileCache[key];
                });
            }
        }
        
        cleanupBeforeUnload() {
            // Clean up event listeners and large objects
            this.$element.off();
            this.abortActiveRequests();
            this.fileCache = null;
            this.files = null;
            this.openTabs = null;
        }
        
        abortActiveRequests() {
            // Abort all pending AJAX requests
            if (this.activeRequests && this.activeRequests.length > 0) {
                this.activeRequests.forEach(request => {
                    if (request && request.abort) {
                        request.abort();
                    }
                });
                this.activeRequests = [];
            }
        }
        
        removeRequest(request) {
            const index = this.activeRequests.indexOf(request);
            if (index > -1) {
                this.activeRequests.splice(index, 1);
            }
        }
    }
    
    // Initialize all viewers on page
    $(document).ready(() => {
        console.log('MCB: Document ready, looking for .maple-code-blocks elements');
        const viewers = [];
        
        $('.maple-code-blocks').each(function() {
            console.log('MCB: Initializing viewer for element:', this);
            try {
                const viewer = new GitHubCodeViewer(this);
                viewers.push(viewer);
                console.log('MCB: Viewer initialized successfully');
            } catch (error) {
                console.error('MCB: Error initializing viewer:', error);
            }
        });
        
        console.log('MCB: Total viewers initialized:', viewers.length);
        
        // Cleanup on page unload to prevent memory leaks
        $(window).on('beforeunload', () => {
            viewers.forEach(viewer => {
                if (viewer && viewer.cleanupBeforeUnload) {
                    viewer.cleanupBeforeUnload();
                }
            });
        });
    });
    
})(jQuery);
