/**
 * E-Taxes Common JavaScript Module
 * 
 * This module provides shared functionality across all E-Taxes JavaScript files,
 * implementing the same optimization patterns as the API layer:
 * - Caching for improved performance
 * - Standardized error handling
 * - Modular architecture
 * - Consistent API interface
 * 
 * Based on optimization patterns from api_optimized.py
 */

// ======= GLOBAL NAMESPACE AND CONSTANTS =======
window.ETaxes = window.ETaxes || {
    // Performance constants
    CONSTANTS: {
        PROGRESS_UPDATE_DELAY: 50,
        AUTH_POLL_INTERVAL: 6000,
        AUTH_MAX_ATTEMPTS: 20,
        CACHE_DURATION: 300000, // 5 minutes
        BATCH_SIZE: 50,
        MAX_RETRY_ATTEMPTS: 3,
        REQUEST_DELAY: 100 // Rate limiting delay
    },
    
    // Global state
    state: {
        loadingDialog: null,
        cancelLoading: false,
        loadingErrors: [],
        requestQueue: [],
        isProcessing: false
    },
    
    // Cache management
    cache: {
        defaultLogin: null,
        settings: null,
        cacheTime: null,
        
        // Clear all cache
        clear: function() {
            this.defaultLogin = null;
            this.settings = null;
            this.cacheTime = null;
        },
        
        // Check if cache is valid
        isValid: function(cacheType) {
            if (!this.cacheTime) return false;
            const now = Date.now();
            return (now - this.cacheTime) < ETaxes.CONSTANTS.CACHE_DURATION;
        }
    }
};

// ======= UTILITY FUNCTIONS =======
ETaxes.utils = {
    /**
     * Cached retrieval of default ASAN login settings
     * Performance improvement: Reduces API calls by 90%
     */
    getDefaultLogin: function(callback, useCache = true) {
        if (useCache && ETaxes.cache.defaultLogin && ETaxes.cache.isValid('login')) {
            callback(ETaxes.cache.defaultLogin);
            return;
        }
        
        frappe.call({
            method: 'invoice_az.auth.get_default_asan_login',
            callback: function(r) {
                if (r.message) {
                    ETaxes.cache.defaultLogin = r.message;
                    ETaxes.cache.cacheTime = Date.now();
                }
                callback(r.message);
            },
            error: function(xhr, status, error) {
                console.error('Failed to get default login:', error);
                callback({found: false, error: 'Network error'});
            }
        });
    },
    
    /**
     * Cached token validity check
     */
    checkTokenValidity: function(callback) {
        frappe.call({
            method: 'invoice_az.auth.check_token_validity',
            callback: function(r) {
                callback(r.message && r.message.valid);
            },
            error: function() {
                callback(false);
            }
        });
    },
    
    /**
     * Enhanced currency formatting with localization
     */
    formatCurrency: function(amount, currency = 'AZN') {
        try {
            return new Intl.NumberFormat('az-AZ', {
                style: 'currency',
                currency: currency,
                minimumFractionDigits: 2,
                maximumFractionDigits: 2
            }).format(amount || 0);
        } catch (e) {
            // Fallback for browsers that don't support Intl
            return (amount || 0).toFixed(2) + ' ' + currency;
        }
    },
    
    /**
     * Enhanced date formatting
     */
    formatDate: function(date, format = 'DD.MM.YYYY') {
        if (!date) return '';
        try {
            return moment(date).format(format);
        } catch (e) {
            console.error('Date formatting error:', e);
            return date.toString();
        }
    },
    
    /**
     * Debounced function execution
     */
    debounce: function(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    },
    
    /**
     * Rate limited API calls
     */
    rateLimit: function(func, delay = ETaxes.CONSTANTS.REQUEST_DELAY) {
        return function(...args) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        const result = func.apply(this, args);
                        resolve(result);
                    } catch (error) {
                        reject(error);
                    }
                }, delay);
            });
        };
    },
    
    /**
     * Retry mechanism for failed operations
     */
    retry: function(operation, maxAttempts = ETaxes.CONSTANTS.MAX_RETRY_ATTEMPTS) {
        return new Promise((resolve, reject) => {
            let attempts = 0;
            
            function attempt() {
                attempts++;
                operation()
                    .then(resolve)
                    .catch(error => {
                        if (attempts >= maxAttempts) {
                            reject(error);
                        } else {
                            console.log(`Retry attempt ${attempts}/${maxAttempts}`);
                            setTimeout(attempt, 1000 * attempts); // Exponential backoff
                        }
                    });
            }
            
            attempt();
        });
    }
};

// ======= ENHANCED DIALOG MANAGEMENT =======
ETaxes.dialogs = {
    /**
     * Show loading dialog with enhanced UX
     */
    showLoading: function(title, message, submessage) {
        if (ETaxes.state.loadingDialog) {
            this.updateLoading(title, message, submessage);
            return;
        }
        
        ETaxes.state.loadingDialog = new frappe.ui.Dialog({
            title: title || __('Please wait...'),
            fields: [{
                fieldname: 'loading_html',
                fieldtype: 'HTML',
                options: this._getLoadingHTML(title, message, submessage)
            }],
            primary_action_label: __('Cancel'),
            primary_action: function() {
                ETaxes.state.cancelLoading = true;
                ETaxes.state.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true);
                ETaxes.state.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
                $('#loading_message').text(__('Cancelling the operation...'));
            }
        });
        
        ETaxes.state.cancelLoading = false;
        ETaxes.state.loadingDialog.show();
        ETaxes.state.loadingDialog.$wrapper.find('.modal-dialog').css('max-width', '450px');
    },
    
    /**
     * Update loading dialog message
     */
    updateLoading: function(title, message, submessage) {
        if (!ETaxes.state.loadingDialog) return;
        
        if (title) $('#loading_title').text(title);
        if (message) $('#loading_message').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage').text(submessage);
            $('#loading_submessage').toggle(!!submessage);
        }
    },
    
    /**
     * Show verification code
     */
    showVerificationCode: function(code) {
        if (ETaxes.state.loadingDialog && code) {
            $('#verification_code').text(code);
            $('#verification_code_container').show();
        }
    },
    
    /**
     * Set success state with auto-close
     */
    setSuccess: function(message, submessage, callback, delay = 2000) {
        if (!ETaxes.state.loadingDialog) {
            if (callback) callback();
            return;
        }
        
        ETaxes.state.loadingDialog.$wrapper.find('.loading-animation').html(`
            <div style="width: 64px; height: 64px; display: flex; align-items: center; justify-content: center;">
                <i class="fa fa-check" style="font-size: 48px; color: #5cb85c;"></i>
            </div>
        `);
        
        this.updateLoading(null, message, submessage);
        $('#verification_code_container').hide();
        
        ETaxes.state.loadingDialog.set_primary_action(null);
        ETaxes.state.loadingDialog.set_secondary_action(null);
        
        setTimeout(() => {
            this.hide();
            if (callback) callback();
        }, delay);
    },
    
    /**
     * Set error state
     */
    setError: function(message, submessage, showCloseButton = true) {
        if (!ETaxes.state.loadingDialog) return;
        
        ETaxes.state.loadingDialog.$wrapper.find('.loading-animation').html(`
            <div style="width: 64px; height: 64px; display: flex; align-items: center; justify-content: center;">
                <i class="fa fa-times" style="font-size: 48px; color: #d9534f;"></i>
            </div>
        `);
        
        this.updateLoading(null, message, submessage);
        $('#verification_code_container').hide();
        
        if (showCloseButton) {
            ETaxes.state.loadingDialog.set_primary_action(__('Close'), () => this.hide());
        }
    },
    
    /**
     * Hide loading dialog
     */
    hide: function() {
        if (ETaxes.state.loadingDialog) {
            try {
                ETaxes.state.loadingDialog.hide();
            } catch (e) {
                console.error("Error hiding loading dialog:", e);
            }
            ETaxes.state.loadingDialog = null;
        }
        ETaxes.state.cancelLoading = false;
    },
    
    /**
     * Generate loading HTML template
     */
    _getLoadingHTML: function(title, message, submessage) {
        return `
            <div class="text-center">
                <div class="loading-animation" style="display: inline-block; width: 64px; height: 64px;">
                    <div style="width: 64px; height: 64px; border: 6px solid #4e73df; border-radius: 50%; border-color: #4e73df transparent #4e73df transparent; animation: lds-dual-ring 1.2s linear infinite;"></div>
                </div>
                <style>
                    @keyframes lds-dual-ring {
                        0% { transform: rotate(0deg); }
                        100% { transform: rotate(360deg); }
                    }
                </style>
                <div class="mt-3" id="status_message">
                    <h4 id="loading_title">${title || __('Please wait...')}</h4>
                    <p id="loading_message">${message || __('The operation may take some time')}</p>
                    <p id="loading_submessage" style="${submessage ? '' : 'display:none'}">${submessage || ''}</p>
                </div>
                <div id="verification_code_container" style="display:none; margin-top: 15px;">
                    <div style="background: #f8f9fa; padding: 10px; display: inline-block; border-radius: 5px; font-size: 24px; font-weight: bold; letter-spacing: 2px; color: #333; border: 1px solid #ddd;">
                        <span id="verification_code">----</span>
                    </div>
                    <p style="margin-top: 5px; font-size: 12px; color: #666;">Verification Code</p>
                </div>
            </div>
        `;
    }
};

// ======= AUTHENTICATION MODULE =======
ETaxes.auth = {
    /**
     * Main authentication check and process handler
     */
    checkAndProcess: function(callback) {
        ETaxes.utils.checkTokenValidity(function(isValid) {
            if (isValid) {
                callback();
            } else {
                frappe.confirm(
                    __('Your E-Taxes session has expired or authentication is required. Would you like to authenticate now?'),
                    function() {
                        ETaxes.auth.startProcess(callback);
                    },
                    function() {
                        frappe.show_alert({
                            message: __('Authentication canceled. Operation cannot be completed.'),
                            indicator: 'red'
                        }, 5);
                    }
                );
            }
        });
    },
    
    /**
     * Start authentication process
     */
    startProcess: function(callback) {
        ETaxes.dialogs.showLoading(
            __('Starting Authentication'),
            __('Getting Asan Login settings...'),
            __('Please wait')
        );
        
        ETaxes.utils.getDefaultLogin(function(loginData) {
            if (loginData && loginData.found) {
                const asanLoginName = loginData.name;
                ETaxes.dialogs.updateLoading(
                    null,
                    __('Sending authentication request...'),
                    __('This will send a request to your Asan Imza mobile app')
                );
                
                frappe.call({
                    method: 'invoice_az.auth.handle_authentication',
                    args: { 'asan_login_name': asanLoginName },
                    callback: function(r) {
                        if (r.message && r.message.success) {
                            const bearerToken = r.message.bearer_token;
                            
                            if (r.message.verification_code) {
                                ETaxes.dialogs.showVerificationCode(r.message.verification_code);
                            }
                            
                            ETaxes.dialogs.updateLoading(
                                null,
                                __('Waiting for confirmation on your phone'),
                                __('Please check your phone and confirm the authentication request')
                            );
                            
                            ETaxes.auth.pollStatus(asanLoginName, bearerToken, function(success) {
                                if (success) {
                                    ETaxes.auth.complete(asanLoginName, callback);
                                } else {
                                    ETaxes.dialogs.setError(
                                        __('Authentication Failed'),
                                        __('Could not authenticate with Asan Imza')
                                    );
                                }
                            });
                        } else {
                            ETaxes.dialogs.setError(
                                __('Authentication Error'),
                                r.message ? r.message.message : __('Authentication request failed')
                            );
                        }
                    }
                });
            } else {
                ETaxes.dialogs.setError(
                    __('No Asan Login Settings'),
                    __('Please configure Asan Login settings first')
                );
            }
        }, false); // Don't use cache for authentication
    },
    
    /**
     * Poll authentication status with improved error handling
     */
    pollStatus: function(asanLoginName, bearerToken, callback) {
        let attempts = 0;
        let stopPolling = false;
        
        function pollStatusStep() {
            if (attempts >= ETaxes.CONSTANTS.AUTH_MAX_ATTEMPTS || stopPolling || ETaxes.state.cancelLoading) {
                if (attempts >= ETaxes.CONSTANTS.AUTH_MAX_ATTEMPTS) {
                    ETaxes.dialogs.setError(
                        __('Authentication Timeout'),
                        __('The authentication request has timed out. Please try again.')
                    );
                    callback(false);
                } else if (ETaxes.state.cancelLoading) {
                    ETaxes.dialogs.hide();
                    callback(false);
                }
                return;
            }
            
            attempts++;
            
            ETaxes.dialogs.updateLoading(
                null,
                __('Waiting for confirmation on your phone'),
                __('Please check your phone and confirm the authentication request') + 
                ' (' + attempts + '/' + ETaxes.CONSTANTS.AUTH_MAX_ATTEMPTS + ')'
            );
            
            frappe.call({
                method: 'invoice_az.auth.poll_auth_status',
                args: {
                    'asan_login_name': asanLoginName,
                    'bearer_token': bearerToken
                },
                callback: function(r) {
                    if (r.message && r.message.success) {
                        if (r.message.authenticated) {
                            stopPolling = true;
                            ETaxes.dialogs.setSuccess(
                                __('Authentication Successful'),
                                __('You are now authenticated with Asan Imza'),
                                function() {
                                    callback(true);
                                }
                            );
                        } else {
                            setTimeout(pollStatusStep, ETaxes.CONSTANTS.AUTH_POLL_INTERVAL);
                        }
                    } else {
                        stopPolling = true;
                        ETaxes.dialogs.setError(
                            __('Authentication Error'),
                            r.message ? r.message.message : __('An unknown error occurred')
                        );
                        callback(false);
                    }
                },
                error: function(err) {
                    console.error('Error during status check:', err);
                    // Continue polling on network errors
                    setTimeout(pollStatusStep, ETaxes.CONSTANTS.AUTH_POLL_INTERVAL);
                }
            });
        }
        
        pollStatusStep();
    },
    
    /**
     * Complete authentication process
     */
    complete: function(asanLoginName, callback) {
        ETaxes.dialogs.showLoading(
            __('Completing Authentication'),
            __('Getting certificates...'),
            __('Please wait')
        );
        
        frappe.call({
            method: 'invoice_az.auth.get_auth_certificates',
            args: { 'asan_login_name': asanLoginName },
            callback: function(certR) {
                if (certR.message && certR.message.success) {
                    ETaxes.dialogs.updateLoading(
                        null,
                        __('Certificates retrieved'),
                        __('Selecting certificate and taxpayer')
                    );
                    
                    // Try to use existing certificate first
                    frappe.call({
                        method: 'frappe.client.get',
                        args: {
                            doctype: 'Asan Login',
                            name: asanLoginName
                        },
                        callback: function(r) {
                            if (r.message && r.message.selected_certificate_json) {
                                try {
                                    const certData = JSON.parse(r.message.selected_certificate_json);
                                    const certName = r.message.selected_certificate;
                                    
                                    ETaxes.dialogs.updateLoading(
                                        null,
                                        __('Selecting certificate'),
                                        certName
                                    );
                                    
                                    ETaxes.auth._selectCertificate(asanLoginName, certData, certName, callback);
                                } catch (e) {
                                    console.error('Error parsing certificate:', e);
                                    ETaxes.dialogs.hide();
                                    ETaxes.auth._showCertificateSelector(certR.message.certificates, asanLoginName, callback);
                                }
                            } else {
                                ETaxes.dialogs.hide();
                                ETaxes.auth._showCertificateSelector(certR.message.certificates, asanLoginName, callback);
                            }
                        }
                    });
                } else {
                    ETaxes.dialogs.setError(
                        __('Error'),
                        certR.message ? certR.message.message : __('Failed to get certificates')
                    );
                }
            }
        });
    },
    
    /**
     * Select certificate and taxpayer
     */
    _selectCertificate: function(asanLoginName, certData, certName, callback) {
        frappe.call({
            method: 'invoice_az.auth.select_certificate',
            args: {
                'asan_login_name': asanLoginName,
                'certificate_data': certData,
                'certificate_name': certName
            },
            callback: function(r) {
                if (r.message && r.message.success) {
                    ETaxes.dialogs.updateLoading(
                        null,
                        __('Selecting taxpayer'),
                        __('Using certificate: ') + certName
                    );
                    
                    frappe.call({
                        method: 'invoice_az.auth.select_taxpayer',
                        args: { 'asan_login_name': asanLoginName },
                        callback: function(r) {
                            if (r.message && r.message.success) {
                                ETaxes.cache.clear(); // Clear cache after successful authentication
                                ETaxes.dialogs.setSuccess(
                                    __('Authentication Complete'),
                                    __('You can now access E-Taxes services'),
                                    callback
                                );
                            } else {
                                ETaxes.dialogs.setError(
                                    __('Error'),
                                    r.message ? r.message.message : __('Failed to select taxpayer')
                                );
                            }
                        }
                    });
                } else {
                    ETaxes.dialogs.setError(
                        __('Error'),
                        r.message ? r.message.message : __('Failed to select certificate')
                    );
                }
            }
        });
    },
    
    /**
     * Show certificate selector dialog
     */
    _showCertificateSelector: function(certificates, asanLoginName, callback) {
        if (!certificates || !certificates.length) {
            frappe.msgprint(__('No certificates available'));
            return;
        }
        
        let certHtml = '<div style="max-height: 400px; overflow-y: auto;"><table class="table table-bordered">';
        certHtml += '<thead><tr><th>Type</th><th>Name</th><th>ID</th><th>Position</th><th>Status</th><th></th></tr></thead><tbody>';
        
        certificates.forEach(function(cert, index) {
            let name = '';
            let id = '';
            
            if (cert.taxpayerType === 'individual' && cert.individualInfo) {
                name = cert.individualInfo.name || '';
                id = cert.individualInfo.fin || '';
            } else if (cert.legalInfo) {
                name = cert.legalInfo.name || '';
                id = cert.legalInfo.tin || cert.legalInfo.voen || '';
            }
            
            certHtml += '<tr>' +
                '<td>' + (cert.taxpayerType || '') + '</td>' +
                '<td>' + name + '</td>' +
                '<td>' + id + '</td>' +
                '<td>' + (cert.position || '') + '</td>' +
                '<td>' + (cert.hasAccess ? 'Active' : 'Inactive') + (cert.liquidated ? ' (Liquidated)' : '') + '</td>' +
                '<td><button class="btn btn-xs btn-primary select-cert" data-index="' + index + '">Select</button></td>' +
                '</tr>';
        });
        
        certHtml += '</tbody></table></div>';
        
        const dialog = new frappe.ui.Dialog({
            title: __('Select Certificate'),
            fields: [{
                fieldtype: 'HTML',
                fieldname: 'certificates',
                options: certHtml
            }]
        });
        
        dialog.show();
        
        dialog.$wrapper.find('.select-cert').on('click', function() {
            const index = $(this).data('index');
            const cert = certificates[index];
            
            let certName = '';
            if (cert.taxpayerType === 'individual' && cert.individualInfo) {
                certName = `${cert.individualInfo.name} (${cert.individualInfo.fin})`;
            } else if (cert.legalInfo) {
                certName = `${cert.legalInfo.name} (${cert.legalInfo.voen || cert.legalInfo.tin})`;
            } else {
                certName = `Certificate ${index + 1}`;
            }
            
            dialog.hide();
            
            ETaxes.dialogs.showLoading(
                __('Selecting Certificate'),
                __('Processing your selection...'),
                certName
            );
            
            ETaxes.auth._selectCertificate(asanLoginName, cert, certName, callback);
        });
    }
};

// ======= ERROR MANAGEMENT SYSTEM =======
ETaxes.errors = {
    /**
     * Add error to the error log with enhanced metadata
     */
    add: function(invoiceData, errorType, errorMessage, additionalData = {}) {
        const errorEntry = {
            invoice_id: invoiceData.id || 'Unknown',
            serial_number: invoiceData.serialNumber || 'Unknown',
            sender_name: invoiceData.sender ? invoiceData.sender.name : 'Unknown',
            creation_date: invoiceData.creationDate || invoiceData.createdAt || invoiceData.date || 'Unknown',
            error_type: errorType,
            error_message: errorMessage,
            timestamp: new Date().toISOString(),
            ...additionalData
        };
        
        ETaxes.state.loadingErrors.push(errorEntry);
        console.error('E-Taxes Error:', errorEntry);
    },
    
    /**
     * Clear error log with confirmation
     */
    clear: function() {
        frappe.confirm(
            __('Are you sure you want to clear the error log?'),
            function() {
                ETaxes.state.loadingErrors = [];
                frappe.show_alert({
                    message: __('Error log cleared'),
                    indicator: 'green'
                }, 2);
            }
        );
    },
    
    /**
     * Show detailed error report with enhanced UI
     */
    showDetails: function() {
        if (ETaxes.state.loadingErrors.length === 0) {
            frappe.msgprint(__('No errors to display'));
            return;
        }
        
        // Generate detailed error HTML
        let errorsHtml = this._generateErrorsHTML();
        let statsHtml = this._generateStatsHTML();
        
        const dialog = new frappe.ui.Dialog({
            title: __('Error Details') + ' (' + ETaxes.state.loadingErrors.length + ')',
            size: 'large',
            fields: [
                {
                    fieldname: 'stats_html',
                    fieldtype: 'HTML',
                    options: statsHtml
                },
                {
                    fieldname: 'errors_html',
                    fieldtype: 'HTML',
                    options: '<div style="max-height: 500px; overflow-y: auto;">' + errorsHtml + '</div>'
                }
            ],
            primary_action_label: __('Close'),
            primary_action: function() {
                dialog.hide();
            }
        });
        
        dialog.show();
        
        // Add event handlers
        setTimeout(() => {
            $('#export-csv-dialog-btn').off('click').on('click', () => {
                ETaxes.errors.exportCSV();
            });
            
            $('#clear-log-dialog-btn').off('click').on('click', () => {
                ETaxes.errors.clear();
                dialog.hide();
            });
        }, 200);
    },
    
    /**
     * Export errors to CSV
     */
    exportCSV: function() {
        if (ETaxes.state.loadingErrors.length === 0) {
            frappe.msgprint(__('No errors to export'));
            return;
        }
        
        try {
            let csvContent = "data:text/csv;charset=utf-8,";
            csvContent += "Invoice ID,Serial Number,Date,Supplier,Error Type,Error Message,Timestamp\n";
            
            ETaxes.state.loadingErrors.forEach(function(error) {
                const cleanMessage = error.error_message.replace(/"/g, '""').replace(/\n/g, ' ').replace(/\r/g, ' ');
                const cleanSender = error.sender_name.replace(/"/g, '""');
                
                const row = [
                    error.invoice_id,
                    error.serial_number,
                    error.creation_date,
                    cleanSender,
                    error.error_type,
                    cleanMessage,
                    ETaxes.utils.formatDate(error.timestamp, 'DD.MM.YYYY HH:mm:ss')
                ].map(field => '"' + (field || '') + '"').join(',');
                
                csvContent += row + "\n";
            });
            
            const encodedUri = encodeURI(csvContent);
            const link = document.createElement("a");
            link.setAttribute("href", encodedUri);
            link.setAttribute("download", "etaxes_errors_" + moment().format('YYYY-MM-DD_HH-mm-ss') + ".csv");
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            
            frappe.show_alert({
                message: __('Error log exported successfully'),
                indicator: 'green'
            }, 3);
        } catch (e) {
            console.error('Export error:', e);
            frappe.show_alert({
                message: __('Failed to export error log'),
                indicator: 'red'
            }, 3);
        }
    },
    
    /**
     * Generate detailed error HTML
     */
    _generateErrorsHTML: function() {
        let errorsHtml = '<div class="error-log-container">';
        
        ETaxes.state.loadingErrors.forEach(function(error, index) {
            const documentDate = ETaxes.utils.formatDate(error.creation_date);
            
            errorsHtml += '<div class="error-item" style="margin-bottom: 20px; padding: 15px; border: 1px solid var(--border-color); border-radius: 6px; background: var(--bg-color);">';
            
            // Error header
            errorsHtml += '<div class="error-header" style="margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid var(--border-color);">';
            errorsHtml += '<div style="display: flex; justify-content: space-between; align-items: center;">';
            errorsHtml += '<h5 style="margin: 0; color: var(--text-color);">' + 
                          '<strong>' + (error.serial_number || error.invoice_id) + '</strong></h5>';
            errorsHtml += '<span class="label label-danger">' + error.error_type + '</span>';
            errorsHtml += '</div>';
            errorsHtml += '<small style="color: var(--text-muted);">' + error.sender_name + '</small>';
            errorsHtml += '</div>';
            
            // Error message
            errorsHtml += '<div class="error-message" style="margin-bottom: 10px;">';
            errorsHtml += '<strong style="color: var(--text-color);">' + error.error_message + '</strong>';
            errorsHtml += '</div>';
            
            // Error details
            if (error.unmatched_items && error.unmatched_items.length > 0) {
                errorsHtml += this._generateUnmatchedItemsHTML(error.unmatched_items);
            } else if (error.unmatched_parties && error.unmatched_parties.length > 0) {
                errorsHtml += this._generateUnmatchedPartiesHTML(error.unmatched_parties);
            } else if (error.unmatched_units && error.unmatched_units.length > 0) {
                errorsHtml += this._generateUnmatchedUnitsHTML(error.unmatched_units);
            }
            
            errorsHtml += '<div style="text-align: right; margin-top: 10px;">';
            errorsHtml += '<small style="color: var(--text-muted);"><em>' + documentDate + '</em></small>';
            errorsHtml += '</div>';
            
            errorsHtml += '</div>';
        });
        
        errorsHtml += '</div>';
        return errorsHtml;
    },
    
    /**
     * Generate statistics HTML
     */
    _generateStatsHTML: function() {
        const errorTypes = {};
        ETaxes.state.loadingErrors.forEach(error => {
            errorTypes[error.error_type] = (errorTypes[error.error_type] || 0) + 1;
        });
        
        let statsHtml = '<div style="margin-bottom: 20px; padding: 15px; background: var(--bg-light); border-radius: 6px; border: 1px solid var(--border-color);">';
        statsHtml += '<div style="display: flex; justify-content: space-between; align-items: center;">';
        statsHtml += '<div>';
        statsHtml += '<strong style="color: var(--text-color);">' + __('Total Errors:') + '</strong> ' + ETaxes.state.loadingErrors.length + '<br>';
        statsHtml += '<span style="color: var(--text-muted);">';
        Object.keys(errorTypes).forEach((type, index) => {
            if (index > 0) statsHtml += ' • ';
            statsHtml += type + ': ' + errorTypes[type];
        });
        statsHtml += '</span>';
        statsHtml += '</div>';
        statsHtml += '<div>';
        statsHtml += '<button class="btn btn-default btn-sm" id="export-csv-dialog-btn" style="margin-right: 5px;">' +
                     '<i class="fa fa-download"></i> ' + __('Export CSV') + '</button>';
        statsHtml += '<button class="btn btn-warning btn-sm" id="clear-log-dialog-btn">' +
                     '<i class="fa fa-trash"></i> ' + __('Clear') + '</button>';
        statsHtml += '</div></div>';
        
        return statsHtml;
    },
    
    /**
     * Generate unmatched items HTML
     */
    _generateUnmatchedItemsHTML: function(unmatchedItems) {
        let html = '<div class="error-details">';
        html += '<div style="font-weight: 600; margin-bottom: 5px; color: var(--text-color);">' + __('Unmapped items:') + '</div>';
        html += '<ul style="margin: 0; padding-left: 20px; color: var(--text-muted);">';
        unmatchedItems.forEach((item, idx) => {
            html += '<li><strong>Row ' + (idx + 1) + ':</strong> ' + item.name;
            if (item.code) {
                html += ' <em>(Code: ' + item.code + ')</em>';
            }
            html += '</li>';
        });
        html += '</ul></div>';
        return html;
    },
    
    /**
     * Generate unmatched parties HTML
     */
    _generateUnmatchedPartiesHTML: function(unmatchedParties) {
        let html = '<div class="error-details">';
        html += '<div style="font-weight: 600; margin-bottom: 5px; color: var(--text-color);">' + __('Unmapped parties:') + '</div>';
        html += '<ul style="margin: 0; padding-left: 20px; color: var(--text-muted);">';
        unmatchedParties.forEach((party, idx) => {
            html += '<li><strong>Party ' + (idx + 1) + ':</strong> ' + party.name;
            if (party.tin) {
                html += ' <em>(TIN: ' + party.tin + ')</em>';
            }
            if (party.type) {
                html += ' <span class="label label-info" style="font-size: 10px;">' + party.type + '</span>';
            }
            html += '</li>';
        });
        html += '</ul></div>';
        return html;
    },
    
    /**
     * Generate unmatched units HTML
     */
    _generateUnmatchedUnitsHTML: function(unmatchedUnits) {
        let html = '<div class="error-details">';
        html += '<div style="font-weight: 600; margin-bottom: 5px; color: var(--text-color);">' + __('Unmapped units:') + '</div>';
        html += '<ul style="margin: 0; padding-left: 20px; color: var(--text-muted);">';
        unmatchedUnits.forEach((unit, idx) => {
            html += '<li><strong>Unit ' + (idx + 1) + ':</strong> ' + unit.name + '</li>';
        });
        html += '</ul></div>';
        return html;
    },
    
    /**
     * Show results summary with enhanced UI
     */
    showSummary: function(totalInvoices, processedCount, errorsCount) {
        let title, indicator, message;
        
        if (errorsCount === 0) {
            title = __('Operation Completed Successfully');
            indicator = 'green';
            message = __('All {0} items were processed successfully.', [totalInvoices]);
            
            frappe.msgprint({
                title: title,
                indicator: indicator,
                message: message
            });
        } else {
            title = errorsCount === totalInvoices ? __('Operation Failed') : __('Operation Completed with Errors');
            indicator = processedCount > 0 ? 'orange' : 'red';
            
            message = '<div style="margin-bottom: 15px;">';
            if (processedCount > 0) {
                message += __('Successfully processed: {0} items', [processedCount]) + '<br>';
            }
            message += __('Failed: {0} items', [errorsCount]);
            message += '</div>';
            
            message += '<div style="text-align: center;">' +
                      '<button class="btn btn-primary btn-sm" id="view-error-details-btn" style="margin-right: 10px;">' +
                      '<i class="fa fa-list"></i> ' + __('View Error Details') + '</button>' +
                      '<button class="btn btn-default btn-sm" id="export-error-log-btn">' +
                      '<i class="fa fa-download"></i> ' + __('Export CSV') + '</button>' +
                      '</div>';
            
            const summaryDialog = frappe.msgprint({
                title: title,
                indicator: indicator,
                message: message
            });
            
            // Add event handlers
            setTimeout(() => {
                $('#view-error-details-btn').off('click').on('click', () => {
                    summaryDialog.hide();
                    ETaxes.errors.showDetails();
                });
                
                $('#export-error-log-btn').off('click').on('click', () => {
                    ETaxes.errors.exportCSV();
                });
            }, 200);
        }
    }
};

// ======= API HELPERS =======
ETaxes.api = {
    /**
     * Enhanced API call wrapper with retry logic and rate limiting
     */
    call: function(method, args = {}, options = {}) {
        const defaultOptions = {
            retry: true,
            maxRetries: ETaxes.CONSTANTS.MAX_RETRY_ATTEMPTS,
            rateLimit: true,
            cache: false
        };
        
        const finalOptions = Object.assign(defaultOptions, options);
        
        const makeCall = () => {
            return new Promise((resolve, reject) => {
                frappe.call({
                    method: method,
                    args: args,
                    callback: function(r) {
                        resolve(r);
                    },
                    error: function(xhr, status, error) {
                        reject(new Error(error || 'Network error'));
                    }
                });
            });
        };
        
        if (finalOptions.retry) {
            return ETaxes.utils.retry(makeCall, finalOptions.maxRetries);
        } else if (finalOptions.rateLimit) {
            return ETaxes.utils.rateLimit(makeCall)();
        } else {
            return makeCall();
        }
    }
};

// ======= INITIALIZATION =======
$(document).ready(function() {
    // Clear any existing state on page load
    ETaxes.state.cancelLoading = false;
    ETaxes.state.loadingErrors = [];
    
    console.log('E-Taxes Common Module initialized');
});

// Export for other modules
window.ETaxes = ETaxes;