/**
 * TalkGenAI Job Manager - Generic async job handling
 * Handles polling, progress tracking, and result loading
 */

(function($) {
    'use strict';
    
    /**
     * Generic Job Manager
     */
    window.TalkGenAI_JobManager = {
        /**
         * Safely parse JSON responses that may arrive double-encoded or escaped
         */
        safeParse: function(raw) {
            if (typeof raw !== 'string') {
                return raw;
            }
            
            // Strip BOM and trim
            let txt = raw.replace(/^\uFEFF/, '').trim();
            
            // Handle escaped JSON (WordPress sometimes escapes AJAX responses)
            if (txt.startsWith('\\{') || txt.startsWith('\\[')) {
                // Remove backslashes before special JSON characters
                txt = txt.replace(/\\(["{}\[\]:,])/g, '$1');
            }
            
            // First pass
            try { 
                return JSON.parse(txt); 
            } catch (e1) {}
            
            // Remove wrapping quotes and unescape
            try {
                if ((txt.startsWith('"') && txt.endsWith('"')) || (txt.startsWith("'") && txt.endsWith("'"))) {
                    txt = txt.slice(1, -1);
                }
                txt = txt.replace(/\\"/g, '"').replace(/\\\\/g, '\\');
                return JSON.parse(txt);
            } catch (e2) {}
            // Extract first JSON object/array from noisy text
            try {
                const objStart = txt.indexOf('{');
                const arrStart = txt.indexOf('[');
                let start = -1;
                if (objStart !== -1 && arrStart !== -1) start = Math.min(objStart, arrStart);
                else start = (objStart !== -1 ? objStart : arrStart);
                if (start > -1) {
                    const candidate = txt.slice(start);
                    // Try object then array close scanning fallback
                    try { return JSON.parse(candidate); } catch (e3) {}
                }
            } catch (e4) {}
            return { success: false, data: { message: 'Invalid JSON response' } };
        },
        
        /**
         * Create a new job
         * 
         * @param {string} jobType - Job type ('article', 'app', etc.)
         * @param {object} inputData - Job-specific input data
         * @param {object} callbacks - {onSuccess, onError, onProgress}
         * @returns {Promise}
         */
        createJob: async function(jobType, inputData, callbacks = {}) {
            try {
                // DEBUG: Log what we're sending
                console.log('[TalkGenAI-JS-DEBUG] Creating job:', {
                    jobType: jobType,
                    hasCurrentSpec: !!inputData.current_spec,
                    currentSpecType: inputData.current_spec ? typeof inputData.current_spec : 'undefined',
                    inputDataKeys: Object.keys(inputData)
                });
                
                // CRITICAL FIX: JSON-stringify inputData to preserve nested objects (current_spec)
                // WordPress AJAX flattens nested objects, breaking current_spec structure
                const raw = await $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    dataType: 'text',
                    data: {
                        action: 'talkgenai_create_job',
                        nonce: talkgenai_nonce,
                        job_type: jobType,
                        input_data: JSON.stringify(inputData)
                    }
                });
                const response = this.safeParse(raw);
                // Accept both WP-wrapped ({success:true,data:{...}}) and direct service ({job_id:...})
                let jobId, estimatedTime;
                if (response && response.success && response.data) {
                    jobId = response.data.job_id;
                    estimatedTime = response.data.estimated_time || 60;
                } else if (response && response.job_id) {
                    jobId = response.job_id;
                    estimatedTime = response.estimated_time || 60;
                }
                
                if (jobId) {
                    
                    if (callbacks.onProgress) {
                        callbacks.onProgress({
                            status: 'pending',
                            message: 'Job created successfully',
                            percent: 5
                        });
                    }
                    
                    // Start polling
                    this.pollJob(jobId, callbacks, estimatedTime);
                    
                    return response.data;
                    
                } else {
                    // Check if this is a structured error (e.g., unsupported app type)
                    if (response.data && response.data.ai_message) {
                        // Attach structured data to error object
                        const error = new Error(response.data.message || 'Failed to create job');
                        error.errorData = response.data;
                        // Call error callback with structured data
                        if (callbacks.onError) {
                            callbacks.onError(response.data.message || 'Failed to create job', response.data);
                        }
                        throw error;
                    } else {
                        throw new Error(response.data.message || 'Failed to create job');
                    }
                }
                
            } catch (error) {
                // Only call onError if it hasn't been called yet
                if (callbacks.onError && !error.errorData) {
                    callbacks.onError(error.message || 'Unknown error');
                }
                throw error;
            }
        },
        
        /**
         * Poll job status until completion
         * 
         * @param {string} jobId - Job ID
         * @param {object} callbacks - {onSuccess, onError, onProgress}
         * @param {number} estimatedTime - Estimated time in seconds
         */
        pollJob: function(jobId, callbacks = {}, estimatedTime = 60) {
            // Exponential backoff polling with cap
            let attempts = 0;
            let intervalMs = 1000; // start at 1s
            const maxIntervalMs = 10000; // cap at 10s
            const maxAttempts = Math.ceil((estimatedTime * 2) / 1); // scaled for dynamic interval

            const tick = async () => {
                attempts++;
                
                try {
                    const raw = await $.ajax({
                        url: ajaxurl,
                        type: 'POST',
                        dataType: 'text',
                        data: {
                            action: 'talkgenai_check_job_status',
                            nonce: talkgenai_nonce,
                            job_id: jobId
                        }
                    });
                const response = window.TalkGenAI_JobManager.safeParse(raw);
                
                // Accept both WP-wrapped and direct service statuses
                let status = null;
                if (response && response.success && response.data) {
                    status = response.data;
                } else if (response && (typeof response.status !== 'undefined' || typeof response.job_id !== 'undefined')) {
                    status = response;
                }
                
                if (status) {
                        
                        if (status.status === 'completed') {
                            // Success!
                            
                            if (callbacks.onProgress) {
                                callbacks.onProgress({
                                    status: 'completed',
                                    message: 'Completed!',
                                    percent: 100
                                });
                            }
                            
                            const hasInline = status && status.result && (status.result.article || status.result.article_html);
                            const resultId = status.article_id || status.result_id || (status.result && status.result.id);
                            const emitAndCallback = (payload) => {
                                try { $(document).trigger('talkgenai:article-generated', [payload]); } catch (_) {}
                                if (callbacks.onSuccess) {
                                    callbacks.onSuccess(payload);
                                }
                            };

                            if (hasInline) {
                                emitAndCallback(status.result);
                            } else if (resultId) {
                                try {
                                    const loaded = await window.TalkGenAI_JobManager.loadResult(resultId);
                                    emitAndCallback(loaded.result_data || loaded);
                                } catch (e) {
                                    emitAndCallback(status.result || {});
                                }
                            } else {
                                emitAndCallback(status.result || {});
                            }
                            // Stop polling after completion
                            return;
                            
                        } else if (status.status === 'failed') {
                            // Failed - pass full status so error handler can access ai_message
                            
                            if (callbacks.onError) {
                                callbacks.onError(status.message || 'Job failed', status);
                            }
                            // Stop polling after failure
                            return;
                            
                        } else {
                            // Still processing
                            const percent = Math.min(95, (attempts / maxAttempts) * 100);
                            const elapsed = attempts * 5;
                            
                            if (callbacks.onProgress) {
                                callbacks.onProgress({
                                    status: status.status,
                                    message: `Processing... (${elapsed}s)`,
                                    percent: percent
                                });
                            }
                        }
                        
                    } else {
                        throw new Error('Status check failed: Unable to extract status from response');
                    }
                } catch (error) {
                    if (callbacks.onError) {
                        callbacks.onError(error.message || 'Polling error');
                    }
                    return;
                }

                if (attempts >= maxAttempts) {
                    if (callbacks.onError) {
                        callbacks.onError('Job timeout - taking longer than expected');
                    }
                    return;
                }

                // Schedule next poll with backoff
                intervalMs = Math.min(maxIntervalMs, Math.floor(intervalMs * 1.7));
                setTimeout(tick, intervalMs);
            };

            // Initial poll
            setTimeout(tick, intervalMs);
        },
        
        /**
         * Get results history
         * 
         * @param {string} jobType - Optional: filter by job type
         * @param {number} limit - Optional: number of results
         * @returns {Promise}
         */
        getHistory: async function(jobType = null, limit = 50) {
            try {
                const data = {
                    action: 'talkgenai_get_results_history',
                    nonce: talkgenai_nonce,
                    limit: limit
                };
                
                if (jobType) {
                    data.job_type = jobType;
                }
                
                console.log('🔍 [getHistory] Requesting history with:', data);
                
                const raw = await $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    dataType: 'text',
                    data: data
                });
                
                console.log('📦 [getHistory] Raw response:', raw);
                const response = this.safeParse(raw);
                console.log('📊 [getHistory] Parsed response:', response);
                
                if (response.success) {
                    console.log('✅ [getHistory] Success! Results:', response.data.results);
                    console.log('✅ [getHistory] Results count:', response.data.results ? response.data.results.length : 0);
                    return response.data.results || [];
                } else {
                    console.error('❌ [getHistory] Error in response:', response.data.message);
                    throw new Error(response.data.message || 'Failed to load history');
                }
                
            } catch (error) {
                console.error('❌ [getHistory] Failed to load history:', error);
                throw error;
            }
        },
        
        /**
         * Load specific result
         * 
         * @param {number} resultId - Result ID
         * @returns {Promise}
         */
        loadResult: async function(resultId) {
            try {
                const raw = await $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    dataType: 'text',
                    data: {
                        action: 'talkgenai_load_result',
                        nonce: talkgenai_nonce,
                        result_id: resultId
                    }
                });
                const response = this.safeParse(raw);
                
                if (response.success) {
                    return response.data.result;
                } else {
                    throw new Error(response.data.message || 'Failed to load result');
                }
                
            } catch (error) {
                console.error('Failed to load result:', error);
                throw error;
            }
        },
        
        /**
         * Delete result
         * 
         * @param {number} resultId - Result ID
         * @returns {Promise}
         */
        deleteResult: async function(resultId) {
            try {
                const raw = await $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    dataType: 'text',
                    data: {
                        action: 'talkgenai_delete_result',
                        nonce: talkgenai_nonce,
                        result_id: resultId
                    }
                });
                const response = this.safeParse(raw);
                
                if (response.success) {
                    return true;
                } else {
                    throw new Error(response.data.message || 'Failed to delete result');
                }
                
            } catch (error) {
                console.error('Failed to delete result:', error);
                throw error;
            }
        },
        
        /**
         * Show progress UI
         * 
         * @param {string} message - Progress message
         * @param {number} percent - Progress percentage (0-100)
         */
        showProgress: function(message, percent = 10) {
            let $container = $('#talkgenai-job-progress');

            // If the container exists but is inside a hidden tab, remove it so it
            // gets re-created in the correct (visible) location.
            if ($container.length && !$container.is(':visible') && $container.closest('.talkgenai-article-type-panel:hidden').length) {
                $container.remove();
                $container = $();
            }

            if ($container.length === 0) {
                // Create progress container using CSS classes (tgai-progress)
                $container = $(
                    '<div id="talkgenai-job-progress" class="tgai-progress">' +
                        '<div class="tgai-progress__inner">' +
                            '<div class="tgai-progress__spinner"></div>' +
                            '<span class="tgai-progress__message talkgenai-progress-message">' + message + '</span>' +
                            '<span class="tgai-progress__timer" style="display:none;">0:00</span>' +
                        '</div>' +
                        '<div class="tgai-progress__bar talkgenai-progress-bar" style="width:' + percent + '%;"></div>' +
                    '</div>'
                );

                // Find a good place to insert it
                const $generateBtn = $('#generate-article-btn:visible');
                const $target = $('#article-result-area');

                if ($generateBtn.length) {
                    $generateBtn.after($container);
                } else if ($target.length) {
                    $target.before($container);
                } else {
                    $('#article-output, #app-output, .talkgenai-output').first().before($container);
                }
            }

            // Show container
            $container.show();

            // Update progress bar width (cap at 100% visually)
            var barWidth = Math.min(percent, 100);
            $container.find('.talkgenai-progress-bar').css('width', barWidth + '%');

            // Update message text
            $container.find('.talkgenai-progress-message').text(message);
        },

        /**
         * Update the elapsed timer display
         * @param {string} timerText - formatted time string like "0:45 / ~2:40"
         */
        updateProgressTimer: function(timerText) {
            var $timer = $('#talkgenai-job-progress .tgai-progress__timer');
            if ($timer.length) {
                $timer.text(timerText).show();
            }
        },
        
        /**
         * Hide progress UI
         */
        hideProgress: function() {
            const $container = $('#talkgenai-job-progress');
            if ($container.length) {
                // Show completion message briefly before hiding
                $container.find('.talkgenai-progress-message').text('Complete! Your content is ready.');
                $container.find('.talkgenai-progress-bar').css('width', '100%');
                $container.find('.tgai-progress__timer').hide();

                setTimeout(() => {
                    $container.fadeOut(400);
                }, 1000);
            }
        },
        
        /**
         * Populate history dropdown
         * 
         * @param {string} selectId - Dropdown element ID
         * @param {array} results - Results array
         * @param {function} labelFormatter - Optional: format label
         */
        populateHistoryDropdown: function(selectId, results, labelFormatter = null) {
            console.log(`🔍 [populateHistoryDropdown] Looking for #${selectId}...`);
            const $select = $('#' + selectId);
            console.log(`🔍 [populateHistoryDropdown] Found elements:`, $select.length);
            
            if ($select.length === 0) {
                console.error(`❌ [populateHistoryDropdown] Dropdown #${selectId} not found in DOM!`);
                console.log('Available select elements:', $('select').map((i, el) => el.id).get());
                return;
            }
            
            console.log(`📝 [populateHistoryDropdown] Populating #${selectId} with ${results.length} items`);
            $select.empty();
            $select.append('<option value="">-- Select from history --</option>');
            
            let addedCount = 0;
            results.forEach(result => {
                let label = labelFormatter ? 
                    labelFormatter(result) : 
                    `${result.job_type} - ${new Date(result.created_at).toLocaleString()}`;
                
                console.log(`  ➕ Adding option: ${label} (value: ${result.id})`);
                $select.append(`<option value="${result.id}">${label}</option>`);
                addedCount++;
            });
            
            console.log(`✅ [populateHistoryDropdown] Added ${addedCount} options to #${selectId}`);
            console.log(`📊 [populateHistoryDropdown] Final dropdown HTML:`, $select.html().substring(0, 200));
        }
    };
    
})(jQuery);

