/**
 * Approval Module
 * Handles rendering and managing approval UI
 */
(function($, rank) {
    'use strict';
    
    // Constants
    const ISSUE_TYPE_MAPPING = {
        'missing_meta_description': 'Missing Meta Description',
        'short_meta_description': 'Short Meta Description',
        'long_meta_description': 'Long Meta Description',
        'missing_title_tag': 'Missing Title Tag',
        'short_title_tag': 'Short Title Tag',
        'long_title_tag': 'Long Title Tag',
        'missing_alt_tags': 'Missing Alt Tag',
        'broken_links_external': 'Broken External Link',
        'broken_links_internal': 'Broken Internal Link',
        'duplicate_meta_description': 'Duplicate Meta Description',
        'duplicate_title': 'Duplicate Title',
        'long_h1_h2_tag': 'Long H1/H2 Tags',
        'missing_h1_tag': 'Missing H1 Tags',
        'large_images': 'Large Images'
    };
    
    /**
     * Extract URL or path from issue data
     * @param {string} issueDescriptionUrl - The issue description URL
     * @param {Object} issue_data - The issue data object
     * @param {string} api_issue_type - The issue type
     * @returns {string} The extracted URL or path
     */
    function extractUrlOrPath(issueDescriptionUrl, issue_data, api_issue_type) {
        let urlOrPath = '';
        
        // First try to get the full URL from issue_data.page_url (added by our PHP fix)
        if (issue_data && issue_data.page_url) {
            urlOrPath = issue_data.page_url;
        }
        // If issue_data contains page_path, use that as fallback
        else if (issue_data && issue_data.page_path) {
            urlOrPath = issue_data.page_path;
        }
        // Otherwise extract from the issueDescriptionUrl
        else if (typeof issueDescriptionUrl === 'string') {
            // Check if the URL contains HTML (our PHP fix adds <a> tags)
            if (issueDescriptionUrl.includes('<a href="')) {
                // Extract the URL from the href attribute
                const hrefMatch = issueDescriptionUrl.match(/<a href="([^"]+)"/);
                if (hrefMatch && hrefMatch[1]) {
                    urlOrPath = hrefMatch[1];
                } else {
                    // If we can't extract the href, use the text content
                    const textMatch = issueDescriptionUrl.replace(/<[^>]+>/g, '');
                    urlOrPath = textMatch.trim();
                }
            } else {
                // Try to extract a URL or path pattern
                const urlMatch = issueDescriptionUrl.match(/https?:\/\/[^\s]+|\/[^\s]+/);
                if (urlMatch) {
                    urlOrPath = urlMatch[0];
                } else {
                    // If no URL/path pattern found, use the whole description
                    urlOrPath = issueDescriptionUrl;
                    
                    // Remove any raw issue type prefixes
                    if (api_issue_type && urlOrPath.includes(api_issue_type + ':')) {
                        urlOrPath = urlOrPath.replace(api_issue_type + ':', '').trim();
                    }
                    
                    // Remove any descriptive text after a hyphen (e.g., "- Long title")
                    if (urlOrPath.includes(' - ')) {
                        urlOrPath = urlOrPath.split(' - ')[0].trim();
                    }
                }
            }
        }
        
        return urlOrPath;
    }
    
    /**
     * Process solutions array into a standardized format
     * @param {Array|string|Object} solutionsArray - The solutions data
     * @returns {Object} Processed solutions data with HTML and metadata
     */
    function processSolutions(solutionsArray, rowKey) {
        let solutionDisplayHtml = '';
        let isMultipleChoice = false;
        let processedSolutions = [];
        
        // Process solutions into simple strings
        if (Array.isArray(solutionsArray)) {
            // Convert each item in the array to a string
            processedSolutions = solutionsArray.map(item => {
                if (typeof item === 'string') {
                    return item;
                } else if (item && typeof item === 'object') {
                    // If it's an object with solution_value, use that
                    if (item.solution_value) {
                        return item.solution_value;
                    } else {
                        // Otherwise try to stringify it
                        return JSON.stringify(item);
                    }
                }
                return String(item);
            });
            isMultipleChoice = processedSolutions.length > 1;
        } else if (typeof solutionsArray === 'string') {
            processedSolutions = [solutionsArray];
            isMultipleChoice = false;
        } else if (solutionsArray && typeof solutionsArray === 'object') {
            // Single object
            if (solutionsArray.solution_value) {
                processedSolutions = [solutionsArray.solution_value];
            } else {
                processedSolutions = [JSON.stringify(solutionsArray)];
            }
            isMultipleChoice = false;
        }
        
        // Generate HTML for solutions
        if (processedSolutions.length > 0) {
            if (processedSolutions.length > 1) {
                // Multiple solutions - show as approval buttons with "or" between them
                solutionDisplayHtml = `<h4>Choose fix:</h4>`;
                
                processedSolutions.forEach((sol, index) => {
                    // Add the button
                    solutionDisplayHtml += `
                        <div class="rank-solution-button-container" style="margin-bottom: 10px; clear: both; width: 100%;">
                            <button class="button button-primary rank-solution-approve-btn" style="width: 100%; text-align: left; white-space: normal; height: auto; padding: 8px 12px;" data-solution="${rank.helpers.escapeHtml(sol)}">
                               ${rank.helpers.escapeHtml(sol.length > 200 ? sol.substring(0, 200) + '...' : sol)}
                            </button>
                        </div>`;
                    
                    // Add "or:" after all buttons except the last one
                    if (index < processedSolutions.length - 1) {
                        solutionDisplayHtml += `<p style="text-align: left; margin: 10px 0; font-weight: bold;">or:</p>`;
                    }
                });
            } else {
                // Single solution - show as a button with heading
                solutionDisplayHtml = `<h4>Click button to approve fix:</h4>
                    <div class="rank-solution-button-container" style="width: 100%;">
                        <button class="button button-primary rank-solution-approve-btn" style="width: 100%; text-align: left; white-space: normal; height: auto; padding: 8px 12px;" data-solution="${rank.helpers.escapeHtml(processedSolutions[0])}">
                            ${rank.helpers.escapeHtml(processedSolutions[0].length > 200 ? processedSolutions[0].substring(0, 200) + '...' : processedSolutions[0])}
                        </button>
                    </div>`;
            }
        } else {
            solutionDisplayHtml = '<p>No solution proposed.</p>';
        }
        
        return {
            html: solutionDisplayHtml,
            isMultipleChoice: isMultipleChoice,
            processedSolutions: processedSolutions
        };
    }
    
    /**
     * Get the chosen solution text from the UI or original data
     * @param {jQuery} $itemContainer - The jQuery container element
     * @param {string} rowKey - The row key
     * @param {Array|string|Object} solutionsArray - The original solutions data
     * @returns {string} The chosen solution text
     */
    function getChosenSolutionText($itemContainer, rowKey, solutionsArray) {
        // Get the solution text to send
        const radioGroupName = 'rank-solution-choice-' + rank.helpers.escapeCssSelector(rowKey);
        const $selectedRadio = $itemContainer.find(`input[name="${radioGroupName}"]:checked`);
        
        if ($selectedRadio.length) {
            // Use the selected radio button value
            return $selectedRadio.val();
        }
        
        // Extract solution from the original data
        if (Array.isArray(solutionsArray) && solutionsArray.length > 0) {
            const firstItem = solutionsArray[0];
            if (typeof firstItem === 'string') {
                return firstItem;
            } else if (firstItem && typeof firstItem === 'object' && firstItem.solution_value) {
                return firstItem.solution_value;
            } else {
                return JSON.stringify(firstItem);
            }
        } else if (typeof solutionsArray === 'string') {
            return solutionsArray;
        } else if (solutionsArray && typeof solutionsArray === 'object' && solutionsArray.solution_value) {
            return solutionsArray.solution_value;
        }
        
        // If we get here, we couldn't determine a solution
        console.error(`Solution for ${rowKey} is in an unexpected format or missing.`);
        return null;
    }
    
    /**
     * Handle AJAX response for approve/skip actions
     * @param {Object} response - The AJAX response
     * @param {string} itemRowKey - The row key
     * @param {string} action - The action ('approve' or 'skip')
     */
    function handleDecisionResponse(response, itemRowKey, action) {
        if (response.success) {
            // Get the URL from the current row data first (this is the most reliable source)
            let displayUrl = "Unknown URL";
            
            // Check if we have current row data
            if (rank.state && rank.state.currentRowData) {
                const rowData = rank.state.currentRowData;
                
                // First try to get the full URL from issue_data.page_url (added by our PHP fix)
                if (rowData.issue_data && rowData.issue_data.page_url) {
                    displayUrl = rowData.issue_data.page_url;
                }
                // Then try to extract from the URL field which often contains the page path
                else if (rowData.url && typeof rowData.url === 'string') {
                    // Check if the URL contains HTML (our PHP fix adds <a> tags)
                    if (rowData.url.includes('<a href="')) {
                        // Extract the URL from the href attribute
                        const hrefMatch = rowData.url.match(/<a href="([^"]+)"/);
                        if (hrefMatch && hrefMatch[1]) {
                            displayUrl = hrefMatch[1];
                        } else {
                            // If we can't extract the href, use the text content
                            const textMatch = rowData.url.replace(/<[^>]+>/g, '');
                            displayUrl = textMatch.trim();
                        }
                    }
                    // For title and meta description issues, the URL is often in the format "/path/ - Issue type"
                    else {
                        const pathMatch = rowData.url.match(/^\/([^-]+)/);
                        if (pathMatch) {
                            displayUrl = pathMatch[1].trim();
                        }
                        // For broken links, the URL is often the full URL
                        else {
                            const urlMatch = rowData.url.match(/https?:\/\/[^\s]+/);
                            if (urlMatch) {
                                displayUrl = urlMatch[0];
                            } else if (!rowData.url.startsWith("Item:")) {
                                displayUrl = rowData.url;
                            }
                        }
                    }
                }
                
                // If we couldn't extract from URL, try issue_data
                if (displayUrl === "Unknown URL" && rowData.issue_data) {
                    if (rowData.issue_data.page_path && rowData.issue_data.page_path !== 'N/A') {
                        displayUrl = rowData.issue_data.page_path;
                    }
                }
            }
            
            // If we still don't have a URL, try to get it from the response
            if (displayUrl === "Unknown URL" && response.data && response.data.nextRow) {
                const nextRow = response.data.nextRow;
                
                // First try to get the full URL from issue_data.page_url (added by our PHP fix)
                if (nextRow.issue_data && nextRow.issue_data.page_url) {
                    displayUrl = nextRow.issue_data.page_url;
                }
                // Try to extract from nextRow.url
                else if (nextRow.url && typeof nextRow.url === 'string') {
                    // Check if the URL contains HTML (our PHP fix adds <a> tags)
                    if (nextRow.url.includes('<a href="')) {
                        // Extract the URL from the href attribute
                        const hrefMatch = nextRow.url.match(/<a href="([^"]+)"/);
                        if (hrefMatch && hrefMatch[1]) {
                            displayUrl = hrefMatch[1];
                        } else {
                            // If we can't extract the href, use the text content
                            const textMatch = nextRow.url.replace(/<[^>]+>/g, '');
                            displayUrl = textMatch.trim();
                        }
                    } else if (!nextRow.url.startsWith("Item:")) {
                        const urlMatch = nextRow.url.match(/https?:\/\/[^\s]+|\/[^\s]+/);
                        if (urlMatch) {
                            displayUrl = urlMatch[0];
                        } else {
                            displayUrl = nextRow.url;
                        }
                    }
                }
                
                // Try to extract from nextRow.issue_data
                if (displayUrl === "Unknown URL" && nextRow.issue_data) {
                    if (nextRow.issue_data.page_path && nextRow.issue_data.page_path !== 'N/A') {
                        displayUrl = nextRow.issue_data.page_path;
                    }
                }
            }
            
            const emoji = action === 'approve' ? '🔨' : '❌';
            
            // Extract the path from the URL for cleaner display
            let displayPath = displayUrl;
            
            // If it's a full URL, extract just the path
            if (displayUrl.startsWith('http')) {
                try {
                    const urlObj = new URL(displayUrl);
                    displayPath = urlObj.pathname;
                    // Remove leading slash for consistency
                    displayPath = displayPath.replace(/^\//, '');
                } catch (e) {
                    // If URL parsing fails, keep the original
                    console.log("Failed to parse URL:", displayUrl);
                }
            }
            
            // Remove any trailing slashes
            displayPath = displayPath.replace(/\/$/, '');
            
            // Make URL clickable with JavaScript to avoid triggering cancel dialog
            const clickableUrl = `<a href="javascript:void(0);" onclick="window.open('${displayUrl}','_blank');">${displayPath}</a>`;
            
            // Get the solution and issue type
            const api_issue_type = rank.state.issueType;
            const solution_from_post = action === 'approve' ? (rank.state.currentRowData && rank.state.currentRowData.solution ?
                (Array.isArray(rank.state.currentRowData.solution) && rank.state.currentRowData.solution.length > 0 ?
                    (typeof rank.state.currentRowData.solution[0] === 'object' ?
                        rank.state.currentRowData.solution[0].solution_value :
                        rank.state.currentRowData.solution[0]) :
                    rank.state.currentRowData.solution) :
                '') : '';
            
            // Get the item URL if available
            const item_url = rank.state.currentRowData && rank.state.currentRowData.issue_data ?
                rank.state.currentRowData.issue_data.image_url ||
                (rank.state.currentRowData.issue_data.item_specific_url_generic || '') :
                '';
            
            // Make all URLs clickable with JavaScript
            const makeClickable = (url, showFullUrl = false) => {
                if (!url || typeof url !== 'string' || !url.trim()) return '';
                
                // Extract display text (path or filename)
                let displayText = url;
                
                // For broken links, always show the full URL
                if (showFullUrl || api_issue_type === 'broken_links_internal' || api_issue_type === 'broken_links_external') {
                    displayText = url; // Show the full URL
                } else if (url.startsWith('http')) {
                    try {
                        // For full URLs, try to get just the path or filename
                        const urlObj = new URL(url);
                        if (api_issue_type === 'missing_alt_tags') {
                            // For images, show the filename
                            displayText = urlObj.pathname.split('/').pop();
                        } else {
                            // For other URLs, show the path
                            displayText = urlObj.pathname;
                        }
                    } catch (e) {
                        // If URL parsing fails, keep the original
                        console.log("Failed to parse URL for display:", url);
                    }
                }
                
                // Add user-select: text to ensure text can be selected
                return `<a href="javascript:void(0);" onclick="window.open('${url}','_blank');" style="user-select: text; -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text;">${displayText}</a>`;
            };
            
            // Add CSS to ensure text selection is enabled for the log output
            if (!document.getElementById('rank-log-selection-fix')) {
                const style = document.createElement('style');
                style.id = 'rank-log-selection-fix';
                style.textContent = `
                    #rank-log-output p {
                        user-select: text !important;
                        -webkit-user-select: text !important;
                        -moz-user-select: text !important;
                        -ms-user-select: text !important;
                    }
                    #rank-log-output a {
                        user-select: text !important;
                        -webkit-user-select: text !important;
                        -moz-user-select: text !important;
                        -ms-user-select: text !important;
                    }
                `;
                document.head.appendChild(style);
            }
            
            // Make item URL clickable if it exists
            const clickableItemUrl = item_url ? makeClickable(item_url) : '';
            
            let logMessage = '';
            
            if (action === 'skip') {
                logMessage = `${emoji} Skipped URL: ${clickableUrl}`;
            } else if (api_issue_type === 'missing_alt_tags' && item_url) {
                // Format for missing alt tags
                logMessage = `${emoji} Fixing URL: ${clickableUrl} 🩹 fix for ${clickableItemUrl}: "${solution_from_post}"`;
            } else if ((api_issue_type === 'broken_links_internal' || api_issue_type === 'broken_links_external') && item_url) {
                // Format for broken links
                logMessage = `${emoji} Fixing URL: ${clickableUrl} 🩹 replacing this link: ${clickableItemUrl} with: "${solution_from_post}"`;
            } else {
                // General format for other issue types
                logMessage = `${emoji} Fixing URL: ${clickableUrl} 🩹 fix applied: "${solution_from_post}"`;
            }
            
            // Prefer the server's truthful outcome (content/image fixes run
            // synchronously and report real success/skip/error) over the
            // optimistic client-built message.
            if (response.data && response.data.serverLog) {
                logMessage = response.data.serverLog;
            }

            rank.helpers.addLogMessage(logMessage);
            
            // Update credits counter if available in the response
            if (response.data.credits) {
                const $globalCreditStatusArea = $('#rank-global-credit-status');
                if ($globalCreditStatusArea.length) {
                    $globalCreditStatusArea.text(`AI Credits left: ${response.data.credits.remaining} / ${response.data.credits.total}`);
                }
            }
            
            const $approvalArea = rank.elements.approvalArea || $('#rank-approval-area');
            $approvalArea.empty().append(`
                <div class="rank-approval-row">
                    <div class="rank-loading-placeholder">Loading... 5-15 seconds</div>
                </div>
            `); // Show loading placeholder with same structure as approval row
            rank.processing.fetchNextRow();
        } else {
            const errorType = action === 'approve' ? 'approving' : 'skipping';
            rank.helpers.showNotice(`Error ${errorType} item: ${response.data.message || response.data || 'Unknown error'}`, 'error');
            rank.helpers.addLogMessage(`Error ${errorType} item ${itemRowKey}: ${response.data.message || response.data || 'Unknown error'}`);
        }
    }
    
    // Render approval row
    function renderApprovalRow(rowData) {
        // rowData is response.data.nextRow from processing.js
        
        // Store the current row data in the state for later use
        if (rank.state) {
            rank.state.currentRowData = rowData;
        }

        const { rowKey, url: issueDescriptionUrl, solution: solutionsArray, issue_data } = rowData;
        const page_path = issue_data && issue_data.page_path ? issue_data.page_path : 'N/A';
        const api_issue_type = rank.state.issueType;
        
        // Get the prettier display string for the issue type
        const issueTypeDisplay = ISSUE_TYPE_MAPPING[api_issue_type] ||
                                (rank_ajax_obj.issue_type_labels && api_issue_type && rank_ajax_obj.issue_type_labels[api_issue_type]) ||
                                api_issue_type || 'Issue';
        
        // Extract URL or path
        let urlOrPath = '';
        
        // For broken links, extract the URL from issueDescriptionUrl
        if (api_issue_type === 'broken_links_external' || api_issue_type === 'broken_links_internal') {
            // Try to extract just the URL from the description
            const urlMatch = issueDescriptionUrl.match(/https?:\/\/[^\s]+/);
            if (urlMatch) {
                // Found a URL, use it
                urlOrPath = urlMatch[0];
                // Remove any trailing characters that aren't part of the URL (like spaces or "on")
                if (urlOrPath.endsWith(' ')) {
                    urlOrPath = urlOrPath.trim();
                }
            } else {
                // Fallback to the original string if no URL found
                urlOrPath = issueDescriptionUrl;
            }
        } else {
            urlOrPath = extractUrlOrPath(issueDescriptionUrl, issue_data, api_issue_type);
        }
        
        // Extract page_url and item_url
        const page_url = issue_data && issue_data.page_url ? issue_data.page_url : null;
        let item_url = null;
        if (api_issue_type === 'missing_alt_tags' && issue_data && issue_data.image_url) {
            item_url = issue_data.image_url;
        }
        
        // Process solutions
        const solutionData = processSolutions(solutionsArray, rowKey);
        
        // Create the approval row
        let itemInfoContent = '';
        
        // Special formatting for broken links
        if (api_issue_type === 'broken_links_external' || api_issue_type === 'broken_links_internal') {
            const linkType = api_issue_type === 'broken_links_external' ? 'external' : 'internal';
            itemInfoContent = `
                <strong>Broken ${linkType} link on this page:</strong> ${page_path}<br>
                <strong>Broken link to replace:</strong> ${urlOrPath}
            `;
        } else {
            itemInfoContent = `<strong>${issueTypeDisplay}:</strong> ${urlOrPath}`;

            // For image alt tags, show a thumbnail of the image being fixed so
            // the user can see what they're writing alt text for. item_url holds
            // the image URL (from issue_data.image_url) for missing_alt_tags.
            if (api_issue_type === 'missing_alt_tags' && typeof item_url === 'string' && item_url.startsWith('http')) {
                itemInfoContent += `
                    <div class="rank-alt-thumbnail" style="margin-top: 8px;">
                        <img src="${rank.helpers.escapeHtml(item_url)}" alt="Image preview" style="max-width: 400px; max-height: 400px; border: 1px solid #ddd; border-radius: 3px; vertical-align: middle;">
                    </div>`;
            }
        }

        // Single editable fix field. We take only the first solution from the
        // API response and let the user edit it before submitting.
        const fixValue = (solutionData.processedSolutions && solutionData.processedSolutions.length > 0)
            ? solutionData.processedSolutions[0]
            : '';

        const $approvalRow = $(`
            <div class="rank-approval-row" data-row-id="${rowKey}">
                <div class="rank-item-info">
                    ${itemInfoContent}
                </div>
                <div class="rank-solution-options">
                    <h4>Submit fix with button below. You can edit it first.</h4>
                    <textarea class="rank-solution-input" rows="3">${rank.helpers.escapeHtml(fixValue)}</textarea>
                    <div class="rank-actions">
                        <button class="button button-primary rank-solution-submit-btn">Submit fix</button>
                        <button class="button rank-skip-btn">❌ Skip</button>
                    </div>
                </div>
            </div>
        `);
        
        const $approvalArea = rank.elements.approvalArea || $('#rank-approval-area');
        if (!$approvalArea.length) {
            console.error("Approval area element not found!");
            rank.helpers.showNotice('Error: UI element for displaying items is missing.', 'error');
            return;
        }
        $approvalArea.empty().append($approvalRow).show();
        
        // Attach event handler for the submit button. Reads the (possibly
        // edited) value from the editable fix field.
        $approvalRow.find('.rank-solution-submit-btn').on('click', function() {
            const $button = $(this);
            const solutionText = $approvalRow.find('.rank-solution-input').val();

            // Add spinner and disable button
            $button.prop('disabled', true);
            const originalText = $button.html();
            $button.html('<span class="spinner is-active" style="float:left; margin:0 8px 0 0;"></span>' + originalText);

            approveItem(rowKey, solutionText, page_url, item_url, api_issue_type);
        });
        
        $approvalRow.find('.rank-skip-btn').on('click', function() {
            skipItem(rowKey, page_url, item_url, api_issue_type);
        });
    }
    
    // Approve an item (records decision as approved)
    function approveItem(itemRowKey, itemSolution, page_url, item_url, api_issue_type) {
        // Find the button that was clicked (if it's still in the DOM)
        const $button = $('.rank-solution-submit-btn, .rank-solution-approve-btn[data-solution="' + rank.helpers.escapeHtml(itemSolution) + '"]');
        
        rank.helpers.trackAjaxRequest($.ajax({
            url: rank_ajax_obj.ajax_url,
            type: 'POST',
            data: {
                action: 'rank_record_decision',
                nonce: rank_ajax_obj.nonce,
                batchId: rank.state.batchId,
                rowKey: itemRowKey,
                approved: true,
                solution: itemSolution,
                page_url: page_url,
                item_url: item_url,
                api_issue_type: api_issue_type,
                // For image fixes, the server uses this to render
                // "now X smaller" in the log. Optional — server falls back
                // gracefully if missing.
                api_content: (function() {
                    if (rank.state.currentRowData
                        && Array.isArray(rank.state.currentRowData.solution)
                        && rank.state.currentRowData.solution.length > 0
                        && rank.state.currentRowData.solution[0]
                        && typeof rank.state.currentRowData.solution[0] === 'object'
                        && rank.state.currentRowData.solution[0].api_content) {
                        return rank.state.currentRowData.solution[0].api_content;
                    }
                    return null;
                })()
            },
            dataType: 'json',
            success: function(response) {
                handleDecisionResponse(response, itemRowKey, 'approve');
            },
            error: function(jqXHR, textStatus, errorThrown) {
                // If the request was aborted, handle silently
                if (textStatus === 'abort') {
                    return; // Exit silently without showing error message
                }
                
                // If the button is still in the DOM, restore it
                if ($button.length) {
                    const originalText = $button.text();
                    $button.html(originalText).prop('disabled', false);
                }
                
                rank.helpers.showNotice(`Error approving item: ${textStatus}. ${jqXHR.responseText}`, 'error');
                rank.helpers.addLogMessage(`AJAX Error approving item ${itemRowKey}: ${textStatus} - ${errorThrown}. Response: ${jqXHR.responseText}`);
            }
        }));
    }
    
    // Skip an item (records decision as not approved)
    function skipItem(itemRowKey, page_url, item_url, api_issue_type) {
        rank.helpers.trackAjaxRequest($.ajax({
            url: rank_ajax_obj.ajax_url,
            type: 'POST',
            data: {
                action: 'rank_record_decision',
                nonce: rank_ajax_obj.nonce,
                batchId: rank.state.batchId,
                rowKey: itemRowKey,
                approved: false,
                solution: '',
                page_url: page_url,
                item_url: item_url,
                api_issue_type: api_issue_type
            },
            dataType: 'json',
            success: function(response) {
                handleDecisionResponse(response, itemRowKey, 'skip');
            },
            error: function(jqXHR, textStatus, errorThrown) {
                // If the request was aborted, handle silently
                if (textStatus === 'abort') {
                    return; // Exit silently without showing error message
                }
                
                rank.helpers.showNotice(`Error skipping item: ${textStatus}. ${jqXHR.responseText}`, 'error');
                rank.helpers.addLogMessage(`AJAX Error skipping item ${itemRowKey}: ${textStatus} - ${errorThrown}. Response: ${jqXHR.responseText}`);
            }
        }));
    }
    
    // Initialize the module
    function init() {
        // No initialization needed for this module
    }
    
    // Reset the approval UI and clear any current row data
    function resetApprovalUI() {
        // Clear any approval area content
        if (rank.elements.approvalArea) {
            rank.elements.approvalArea.empty();
        }
        
        // Reset any stored state related to the current row
        if (rank.state) {
            rank.state.currentRowKey = null;
            rank.state.currentRowData = null;
        }
    }
    
    // Expose public methods
    rank.approval = {
        init: init,
        renderApprovalRow: renderApprovalRow,
        resetApprovalUI: resetApprovalUI,
        // New function to append rows for batch manual listing
        appendApprovalRow: function(rowData) {
            // This function is largely a copy of renderApprovalRow, but uses .append()
            // and might have slightly different styling or less emphasis if part of a long list.
            // For now, let's keep it very similar for consistent item display.


            const { rowKey, url: issueDescriptionUrl, solution: solutionsArray, issue_data } = rowData;
            const page_path = issue_data && issue_data.page_path ? issue_data.page_path : 'N/A';
            const api_issue_type = rank.state.issueType;
            
            // Map issue types to their prettier display strings
            const issueTypeMapping = {
                'missing_meta_description': 'Missing Meta Descriptions',
                'short_meta_description': 'Short Meta Descriptions',
                'long_meta_description': 'Long Meta Descriptions',
                'missing_title_tag': 'Missing Title Tags',
                'short_title_tag': 'Short Title Tags',
                'long_title_tag': 'Long Title Tags',
                'missing_alt_tags': 'Missing Alt Tags',
                'broken_links_external': 'Broken External Links',
                'broken_links_internal': 'Broken Internal Links',
                'duplicate_meta_description': 'Duplicate Meta Descriptions',
                'duplicate_title': 'Duplicate Title Tags',
                'long_h1_h2_tag': 'Long H1/H2 Tags',
                'missing_h1_tag': 'Missing H1 Tags',
                'large_images': 'Large Images'
            };
            
            // Get the prettier display string for the issue type
            const issueTypeDisplay = issueTypeMapping[api_issue_type] ||
                                    (rank_ajax_obj.issue_type_labels && api_issue_type && rank_ajax_obj.issue_type_labels[api_issue_type]) ||
                                    api_issue_type || 'Issue';
                                     
            // Extract just the URL or path from the issue description
            let urlOrPath = '';
            
            // For broken links, extract the URL from issueDescriptionUrl
            if (api_issue_type === 'broken_links_external' || api_issue_type === 'broken_links_internal') {
                // Try to extract just the URL from the description
                const urlMatch = issueDescriptionUrl.match(/https?:\/\/[^\s]+/);
                if (urlMatch) {
                    // Found a URL, use it
                    urlOrPath = urlMatch[0];
                    // Remove any trailing characters that aren't part of the URL (like spaces or "on")
                    if (urlOrPath.endsWith(' ')) {
                        urlOrPath = urlOrPath.trim();
                    }
                } else {
                    // Fallback to the original string if no URL found
                    urlOrPath = issueDescriptionUrl;
                }
            }
            // Otherwise use the standard extraction logic
            else {
                // If issue_data contains page_path, use that directly
                if (issue_data && issue_data.page_path) {
                    urlOrPath = issue_data.page_path;
                }
                // Otherwise extract from the issueDescriptionUrl
                else if (typeof issueDescriptionUrl === 'string') {
                    // Try to extract a URL or path pattern
                    const urlMatch = issueDescriptionUrl.match(/https?:\/\/[^\s]+|\/[^\s]+/);
                    if (urlMatch) {
                        urlOrPath = urlMatch[0];
                    } else {
                        // If no URL/path pattern found, use the whole description
                        urlOrPath = issueDescriptionUrl;
                        
                        // Remove any raw issue type prefixes
                        if (api_issue_type && urlOrPath.includes(api_issue_type + ':')) {
                            urlOrPath = urlOrPath.replace(api_issue_type + ':', '').trim();
                        }
                        
                        // Remove any descriptive text after a hyphen (e.g., "- Long title")
                        if (urlOrPath.includes(' - ')) {
                            urlOrPath = urlOrPath.split(' - ')[0].trim();
                        }
                    }
                }
            }

            const page_url = issue_data && issue_data.page_url ? issue_data.page_url : null;
            let item_url = null;
            if (api_issue_type === 'missing_alt_tags' && issue_data && issue_data.image_url) {
                item_url = issue_data.image_url;
            }

            let solutionDisplayHtml = '';
            let isMultipleChoice = Array.isArray(solutionsArray) && solutionsArray.length > 0;
            let processedSolutions = [];

            // Process solutions into simple strings
            if (Array.isArray(solutionsArray)) {
                processedSolutions = solutionsArray.map(item => {
                    if (typeof item === 'string') {
                        return item;
                    } else if (item && typeof item === 'object') {
                        if (item.solution_value) {
                            return item.solution_value;
                        } else {
                            return JSON.stringify(item);
                        }
                    }
                    return String(item);
                });
            } else if (typeof solutionsArray === 'string') {
                processedSolutions = [solutionsArray];
            } else if (solutionsArray && typeof solutionsArray === 'object') {
                if (solutionsArray.solution_value) {
                    processedSolutions = [solutionsArray.solution_value];
                } else {
                    try {
                        processedSolutions = [JSON.stringify(solutionsArray)];
                    } catch (e) {
                        processedSolutions = ['Solution in object format (cannot display)'];
                    }
                }
            }

            // Generate HTML for solutions
            if (processedSolutions.length > 0) {
                if (processedSolutions.length > 1) {
                    // Multiple solutions - show as approval buttons with "or" between them
                    solutionDisplayHtml = `<h4>Choose fix:</h4>`;
                    
                    processedSolutions.forEach((sol, index) => {
                        // Add the button
                        solutionDisplayHtml += `
                            <div class="rank-solution-button-container" style="margin-bottom: 10px; clear: both; width: 100%;">
                                <button class="button button-primary rank-solution-approve-btn" style="width: 100%; text-align: left; white-space: normal; height: auto; padding: 8px 12px;" data-solution="${rank.helpers.escapeHtml(sol)}">
                                    ✅ Approve: ${rank.helpers.escapeHtml(sol.length > 200 ? sol.substring(0, 200) + '...' : sol)}
                                </button>
                            </div>`;
                        
                        // Add "or:" after all buttons except the last one
                        if (index < processedSolutions.length - 1) {
                            solutionDisplayHtml += `<p style="text-align: center; margin: 10px 0; font-weight: bold;">or:</p>`;
                        }
                    });
                } else {
                    // Single solution - show as a button with heading
                    solutionDisplayHtml = `<h4>Click button to approve fix:</h4>
                        <div class="rank-solution-button-container" style="width: 100%;">
                            <button class="button button-primary rank-solution-approve-btn" style="width: 100%; text-align: left; white-space: normal; height: auto; padding: 8px 12px;" data-solution="${rank.helpers.escapeHtml(processedSolutions[0])}">
                                ✅ Approve: ${rank.helpers.escapeHtml(processedSolutions[0].length > 200 ? processedSolutions[0].substring(0, 200) + '...' : processedSolutions[0])}
                            </button>
                        </div>`;
                }
            } else {
                solutionDisplayHtml = '<p>No solution proposed.</p>';
            }

            // Add a class to distinguish appended rows if needed, e.g., for styling or event handling.
            let itemInfoContent = '';
            
            // Special formatting for broken links
            if (api_issue_type === 'broken_links_external' || api_issue_type === 'broken_links_internal') {
                const linkType = api_issue_type === 'broken_links_external' ? 'external' : 'internal';
                itemInfoContent = `
                    <strong>Broken ${linkType} link on this page:</strong> ${page_path}<br>
                    <strong>Broken link to replace:</strong> ${urlOrPath}
                `;
            } else {
                itemInfoContent = `<strong>${issueTypeDisplay}:</strong> ${urlOrPath}`;

                // For image alt tags, show a thumbnail of the image being fixed.
                if (api_issue_type === 'missing_alt_tags' && typeof item_url === 'string' && item_url.startsWith('http')) {
                    itemInfoContent += `
                        <div class="rank-alt-thumbnail" style="margin-top: 8px;">
                            <img src="${rank.helpers.escapeHtml(item_url)}" alt="Image preview" style="max-width: 120px; max-height: 120px; border: 1px solid #ddd; border-radius: 3px; vertical-align: middle;">
                        </div>`;
                }
            }
            
            const $approvalRow = $(`
                <div class="rank-approval-row rank-appended-item" data-row-id="${rowKey}">
                    <div class="rank-item-info">
                        ${itemInfoContent}
                    </div>
                    <div class="rank-solution-options">
                        ${solutionDisplayHtml}
                    </div>
                    <div class="rank-actions">
                        <button class="button rank-skip-btn">Skip</button>
                    </div>
                    <hr class="rank-item-divider">
                </div>
            `);
            
            const $approvalArea = rank.elements.approvalArea || $('#rank-approval-area');
            if (!$approvalArea.length) {
                console.error("RANK: Approval area element (#rank-approval-area) not found for appending!");
                rank.helpers.showNotice('Error: UI element for displaying items is missing.', 'error');
                return;
            }
            // Key difference: .append() instead of .empty().append()
            $approvalArea.append($approvalRow).show();
            console.log("RANK: Approval row appended for", rowKey);
            
            // Event handlers for approve/skip buttons on this specific appended row
            // These are identical to renderApprovalRow's handlers
            // Attach event handlers for solution approval buttons
            $approvalRow.find('.rank-solution-approve-btn').on('click', function() {
                const $button = $(this);
                const solutionText = $button.data('solution');
                
                // Add spinner and disable button
                $button.prop('disabled', true);
                const originalText = $button.html();
                $button.html('<span class="spinner is-active" style="float:left; margin:0 8px 0 0;"></span>' + originalText);
                
                // Call existing approveItem - this will fetchNextRow and replace the list currently
                approveItem(rowKey, solutionText, page_url, item_url, api_issue_type);
            });
            
            $approvalRow.find('.rank-skip-btn').on('click', function() {
                // Similar to approve, skipping an item from the list will currently refresh the view.
                skipItem(rowKey, page_url, item_url, api_issue_type);
            });
        },
        approveItem: approveItem,
        skipItem: skipItem
    };
    
})(jQuery, window.rank = window.rank || {});