<?php
/**
 * Name: Auto Set Featured Image
 * Description: Automatically set first image from post content as featured image only for images uploaded to WordPress media library to save time publishing
 * Category: Content
 * Icon: -
 * UseCases: [
 *   {
 *     "title": "News Blog Automation",
 *     "description": "Automatically set first image in blog posts as featured image so journalists don't have to manually set it for 20+ daily articles."
 *   },
 *   {
 *     "title": "Import Workflow",
 *     "description": "When importing hundreds of posts from old site, automatically assign featured images from content instead of manual assignment."
 *   },
 *   {
 *     "title": "Video Tutorial Site",
 *     "description": "Extract video thumbnails as featured images for video posts, creating consistent archive and category pages."
 *   }
 * ]
 * Added: 2025-10-01
 * Tags: featured-image, thumbnail, automation, content, images
 * WhereToFind: {
 *   "location": "Configure in module settings",
 *   "url": "",
 *   "instructions": "Works automatically when saving posts",
 *   "newTab": false
 * }
 */

// Prevent direct access
if (!defined('ABSPATH')) exit;

class SwitchboardAutoFeaturedImage {

    private $debug_log = [];
    private $debug_post_id = 0;

    public function __construct() {
        add_action('save_post', [$this, 'auto_set_featured_image'], 10, 2);

        // Show debug if admin
        if (current_user_can('manage_options')) {
            add_action('admin_notices', [$this, 'show_debug']);
        }

        // AJAX handlers for bulk apply
        add_action('wp_ajax_switchboard_scan_posts_without_featured', [$this, 'ajax_scan_posts']);
        add_action('wp_ajax_switchboard_bulk_apply_featured_image', [$this, 'ajax_bulk_apply']);

        // Register with data registry
        $this->register_with_data_registry();
    }
    
    /**
     * Register data locations with the data registry
     */
    private function register_with_data_registry() {
        if (class_exists('Switchboard_Data_Registry')) {
            $registry = Switchboard_Data_Registry::get_instance();
            $registry->auto_register($this, __FILE__);
        }
    }
    
    /**
     * Register data locations for cleanup
     */
    public function register_data_locations() {
        return [
            'options' => [
                'switchboard_auto-featured-image_settings'
            ],
            'option_patterns' => [],
            'tables' => [],
            'post_meta' => [],
            'user_meta' => [],
            'transients' => []
        ];
    }
    
    /**
     * Render settings panel
     */
    public function render_settings($settings = []) {
        $selected_post_types = isset($settings['post_types']) ? explode(',', $settings['post_types']) : ['post', 'page'];
        $selected_post_types = array_map('trim', $selected_post_types);

        // Exclude media and system post types
        $all_post_types = get_post_types(['public' => true], 'objects');
        $exclude_types = ['attachment', 'wp_block', 'wp_template', 'wp_template_part', 'wp_navigation'];
        $all_post_types = array_diff_key($all_post_types, array_flip($exclude_types));
        ?>
        <input type="hidden" name="module" value="auto-featured-image">
        <input type="hidden" name="setting_post_types" id="setting_post_types" value="<?php echo esc_attr(implode(',', $selected_post_types)); ?>">

        <div class="sb-sp-group">
            <label class="sb-sp-label"><?php esc_html_e('Select Post Types', 'wpswitchboard'); ?></label>
            <div class="switchboard-tag-selector" data-input-id="setting_post_types">
                <div class="switchboard-selected-tags" id="selected-post-types">
                    <?php foreach ($selected_post_types as $pt_slug):
                        if (isset($all_post_types[$pt_slug])): ?>
                            <span class="switchboard-tag" data-value="<?php echo esc_attr($pt_slug); ?>">
                                <?php echo esc_html($all_post_types[$pt_slug]->label); ?>
                                <span class="remove-tag">×</span>
                            </span>
                        <?php endif;
                    endforeach; ?>
                </div>
                <div class="switchboard-available-tags">
                    <?php foreach ($all_post_types as $pt_slug => $pt_obj):
                        $is_selected = in_array($pt_slug, $selected_post_types) ? 'selected' : ''; ?>
                        <span class="switchboard-tag-option <?php echo esc_attr($is_selected); ?>" data-value="<?php echo esc_attr($pt_slug); ?>">
                            <?php echo esc_html($pt_obj->label); ?>
                        </span>
                    <?php endforeach; ?>
                </div>
            </div>
            <p class="sb-sp-description"><?php esc_html_e('Select post types where first image will be set as featured image.', 'wpswitchboard'); ?></p>
        </div>

        <!-- Bulk Apply Section -->
        <div class="sb-sp-divider"></div>

        <div class="sb-sp-group" style="background: #f9fafb; padding: 20px; border-radius: 8px; border: 1px solid #e5e7eb;">
            <h4 class="sb-sp-heading-sm" style="margin: 0 0 12px 0;"><?php esc_html_e('Apply to Existing Content', 'wpswitchboard'); ?></h4>
            <p class="sb-sp-description" style="margin-bottom: 16px;">
                <?php esc_html_e('Scan existing posts/pages without featured images and automatically set them using the first image in their content.', 'wpswitchboard'); ?>
            </p>

            <div id="bulk-apply-container">
                <button type="button" id="scan-posts-btn" class="sb-module-button sb-module-button-secondary">
                    <?php esc_html_e('Scan for Posts Without Featured Images', 'wpswitchboard'); ?>
                </button>

                <div id="scan-results" style="display: none; margin-top: 16px;">
                    <div class="sb-sp-alert sb-sp-alert-info" style="margin-bottom: 12px;">
                        <span id="scan-summary"></span>
                    </div>
                    <button type="button" id="apply-featured-btn" class="sb-module-button sb-module-button-primary" style="display: none;">
                        <?php esc_html_e('Apply Featured Images', 'wpswitchboard'); ?>
                    </button>
                </div>

                <div id="apply-progress" style="display: none; margin-top: 16px;">
                    <div style="background: #e5e7eb; border-radius: 4px; height: 8px; overflow: hidden; margin-bottom: 8px;">
                        <div id="progress-bar" style="background: var(--primary-500); height: 100%; width: 0%; transition: width 0.3s ease;"></div>
                    </div>
                    <p class="sb-sp-description" id="progress-text" style="margin: 0;"></p>
                </div>

                <div id="apply-results" style="display: none; margin-top: 16px;">
                    <div class="sb-sp-alert sb-sp-alert-success">
                        <span id="apply-summary"></span>
                    </div>
                </div>
            </div>
        </div>

        <script>
        jQuery(document).ready(function($) {
            var postsToProcess = [];
            var processedCount = 0;
            var successCount = 0;
            var skippedCount = 0;
            var failCount = 0;
            var failedPosts = [];

            // Scan for posts
            $('#scan-posts-btn').on('click', function() {
                var $btn = $(this);
                var postTypes = $('#setting_post_types').val();

                $btn.prop('disabled', true).text('<?php esc_html_e('Scanning...', 'wpswitchboard'); ?>');
                $('#scan-results, #apply-progress, #apply-results').hide();

                $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    data: {
                        action: 'switchboard_scan_posts_without_featured',
                        post_types: postTypes,
                        nonce: '<?php echo esc_attr(wp_create_nonce('switchboard_bulk_featured')); ?>'
                    },
                    success: function(response) {
                        $btn.prop('disabled', false).text('<?php esc_html_e('Scan for Posts Without Featured Images', 'wpswitchboard'); ?>');

                        if (response.success) {
                            postsToProcess = response.data.posts;
                            var total = response.data.total;
                            var withImages = response.data.with_images;

                            $('#scan-summary').html(
                                '<strong>' + total + '</strong> <?php esc_html_e('posts found without featured images.', 'wpswitchboard'); ?>' +
                                (withImages > 0 ? '<br><strong>' + withImages + '</strong> <?php esc_html_e('of them have images in content that can be used.', 'wpswitchboard'); ?>' : '<br><?php esc_html_e('None of them have usable images in their content.', 'wpswitchboard'); ?>')
                            );
                            $('#scan-results').show();

                            if (withImages > 0) {
                                $('#apply-featured-btn').show().text('<?php esc_html_e('Apply Featured Images', 'wpswitchboard'); ?> (' + withImages + ')');
                            } else {
                                $('#apply-featured-btn').hide();
                            }
                        } else {
                            alert(response.data.message || '<?php esc_html_e('Scan failed', 'wpswitchboard'); ?>');
                        }
                    },
                    error: function() {
                        $btn.prop('disabled', false).text('<?php esc_html_e('Scan for Posts Without Featured Images', 'wpswitchboard'); ?>');
                        alert('<?php esc_html_e('Connection error. Please try again.', 'wpswitchboard'); ?>');
                    }
                });
            });

            // Apply featured images
            $('#apply-featured-btn').on('click', function() {
                var $btn = $(this);

                if (postsToProcess.length === 0) {
                    alert('<?php esc_html_e('No posts to process', 'wpswitchboard'); ?>');
                    return;
                }

                $btn.prop('disabled', true);
                $('#scan-results').hide();
                $('#apply-progress').show();
                $('#apply-results').hide();

                processedCount = 0;
                successCount = 0;
                skippedCount = 0;
                failCount = 0;
                failedPosts = [];

                processNextPost();
            });

            function processNextPost() {
                if (processedCount >= postsToProcess.length) {
                    // Done
                    $('#apply-progress').hide();
                    var summaryHtml = '<strong><?php esc_html_e('Complete!', 'wpswitchboard'); ?></strong><br>' +
                        successCount + ' <?php esc_html_e('posts updated with featured images', 'wpswitchboard'); ?>';

                    if (skippedCount > 0) {
                        summaryHtml += '<br>' + skippedCount + ' <?php esc_html_e('posts already had featured images (skipped)', 'wpswitchboard'); ?>';
                    }

                    if (failCount > 0) {
                        summaryHtml += '<br><br><strong>' + failCount + ' <?php esc_html_e('posts failed:', 'wpswitchboard'); ?></strong>';
                        summaryHtml += '<ul style="margin: 8px 0 0 16px; padding: 0; list-style: disc;">';
                        failedPosts.forEach(function(item) {
                            summaryHtml += '<li><strong>' + item.title + '</strong>: ' + item.reason + '</li>';
                        });
                        summaryHtml += '</ul>';
                    }

                    $('#apply-summary').html(summaryHtml);
                    $('#apply-results').show();
                    postsToProcess = [];
                    return;
                }

                var post = postsToProcess[processedCount];
                var progress = Math.round((processedCount / postsToProcess.length) * 100);

                $('#progress-bar').css('width', progress + '%');
                $('#progress-text').text('<?php esc_html_e('Processing', 'wpswitchboard'); ?>: ' + post.title + ' (' + (processedCount + 1) + '/' + postsToProcess.length + ')');

                $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    data: {
                        action: 'switchboard_bulk_apply_featured_image',
                        post_id: post.id,
                        nonce: '<?php echo esc_attr(wp_create_nonce('switchboard_bulk_featured')); ?>'
                    },
                    success: function(response) {
                        if (response.success) {
                            if (response.data && response.data.skipped) {
                                skippedCount++;
                            } else {
                                successCount++;
                            }
                        } else {
                            failCount++;
                            failedPosts.push({
                                title: post.title,
                                reason: response.data && response.data.message ? response.data.message : '<?php esc_html_e('Unknown error', 'wpswitchboard'); ?>'
                            });
                        }
                    },
                    error: function() {
                        failCount++;
                        failedPosts.push({
                            title: post.title,
                            reason: '<?php esc_html_e('Connection error', 'wpswitchboard'); ?>'
                        });
                    },
                    complete: function() {
                        processedCount++;
                        processNextPost();
                    }
                });
            }
        });
        </script>
        <?php
    }

    public function auto_set_featured_image($post_id, $post) {
        $this->debug_post_id = $post_id;
        $this->debug_log[] = "=== Auto Featured Image Called ===";
        $this->debug_log[] = "Post ID: {$post_id}";

        // Skip auto-saves and revisions
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            $this->debug_log[] = "Skipped: Auto-save";
            return;
        }

        if (wp_is_post_revision($post_id)) {
            $this->debug_log[] = "Skipped: Revision";
            return;
        }

        // Validate post object
        if (!is_object($post) || !isset($post->post_type, $post->post_content)) {
            $this->debug_log[] = "Skipped: Invalid post object";
            return;
        }

        $this->debug_log[] = "Post Type: {$post->post_type}";

        // Check if post already has featured image
        if (has_post_thumbnail($post_id)) {
            $this->debug_log[] = "Skipped: Already has featured image";
            return;
        }

        // Get settings
        $settings = get_option('switchboard_auto-featured-image_settings', []);
        $this->debug_log[] = "Settings: " . wp_json_encode($settings);

        $post_types = ['post', 'page']; // Default

        if (isset($settings['post_types']) && is_string($settings['post_types']) && !empty($settings['post_types'])) {
            $post_types = array_map('trim', explode(',', $settings['post_types']));
        }

        $this->debug_log[] = "Allowed Post Types: " . implode(', ', $post_types);

        // Check if post type is enabled
        if (!in_array($post->post_type, $post_types)) {
            $this->debug_log[] = "Skipped: Post type not allowed";
            return;
        }

        // Get first image from content (supports both classic and block editor)
        preg_match_all('/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]*>/i', $post->post_content, $matches);

        $this->debug_log[] = "Images found: " . count($matches[1]);

        if (empty($matches[1]) || !is_array($matches[1])) {
            $this->debug_log[] = "Skipped: No images in content";
            return;
        }

        // Try each image until we find one in the media library
        $attachment_id = 0;
        $image_url = '';

        foreach ($matches[1] as $url) {
            $this->debug_log[] = "Checking image: {$url}";

            // Try direct lookup
            $att_id = attachment_url_to_postid($url);

            // If not found, try removing size suffix (-300x200, -1024x768, etc.)
            if (!$att_id) {
                $url_without_size = preg_replace('/-\d+x\d+(\.[a-z]{3,4})$/i', '$1', $url);
                if ($url_without_size !== $url) {
                    $att_id = attachment_url_to_postid($url_without_size);
                    if ($att_id) {
                        $this->debug_log[] = "  Found after removing size suffix";
                    }
                }
            }

            if ($att_id) {
                $attachment_id = $att_id;
                $image_url = $url;
                $this->debug_log[] = "  Attachment ID: {$attachment_id} (found)";
                break;
            } else {
                $this->debug_log[] = "  Not in media library";
            }
        }

        if ($attachment_id) {
            set_post_thumbnail($post_id, $attachment_id);
            $this->debug_log[] = "SUCCESS: Featured image set! (ID: {$attachment_id})";
        } else {
            $this->debug_log[] = "FAILED: No images found in media library";
            $this->debug_log[] = "Note: Only images uploaded to WordPress media library can be used";
        }
    }

    public function show_debug() {
        if (empty($this->debug_log)) {
            return;
        }

        // Only show debug on the post edit screen of the post that was just saved
        global $pagenow, $typenow;
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display-only check for post edit screen
        $current_post_id = isset($_GET['post']) ? intval($_GET['post']) : 0;

        if ($pagenow !== 'post.php' || $current_post_id !== $this->debug_post_id) {
            return;
        }

        echo '<div class="notice notice-info" style="background: #000; color: #0f0; padding: 15px; font-family: monospace; font-size: 11px; white-space: pre-wrap;">';
        echo '<strong style="color: #ff0;">Auto Featured Image Debug</strong><br><br>';
        foreach ($this->debug_log as $log) {
            echo esc_html($log) . "<br>";
        }
        echo '</div>';
    }

    /**
     * AJAX handler: Scan posts without featured images
     */
    public function ajax_scan_posts() {
        check_ajax_referer('switchboard_bulk_featured', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'Permission denied']);
        }

        $post_types_raw = isset($_POST['post_types']) ? sanitize_text_field(wp_unslash($_POST['post_types'])) : 'post,page';
        $post_types = array_map('trim', explode(',', $post_types_raw));

        // Get all published posts without featured images
        $args = [
            'post_type'      => $post_types,
            'post_status'    => 'publish',
            'posts_per_page' => -1,
            'meta_query'     => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Required to find posts without featured images
                'relation' => 'OR',
                [
                    'key'     => '_thumbnail_id',
                    'compare' => 'NOT EXISTS',
                ],
                [
                    'key'     => '_thumbnail_id',
                    'value'   => '',
                    'compare' => '=',
                ],
            ],
            'fields' => 'ids',
        ];

        $post_ids = get_posts($args);
        $posts_data = [];
        $with_images_count = 0;

        foreach ($post_ids as $post_id) {
            // Double-check it doesn't have a featured image (meta_query can miss some edge cases)
            if (has_post_thumbnail($post_id)) {
                continue;
            }

            $post = get_post($post_id);
            $has_usable_image = $this->find_first_media_image($post->post_content) ? true : false;

            if ($has_usable_image) {
                $with_images_count++;
                $posts_data[] = [
                    'id'    => $post_id,
                    'title' => get_the_title($post_id),
                ];
            }
        }

        wp_send_json_success([
            'total'       => count($post_ids),
            'with_images' => $with_images_count,
            'posts'       => $posts_data,
        ]);
    }

    /**
     * AJAX handler: Apply featured image to a single post
     */
    public function ajax_bulk_apply() {
        check_ajax_referer('switchboard_bulk_featured', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'Permission denied']);
        }

        $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;

        if (!$post_id) {
            wp_send_json_error(['message' => 'Invalid post ID']);
        }

        $post = get_post($post_id);

        if (!$post) {
            wp_send_json_error(['message' => 'Post not found']);
        }

        // Skip if already has featured image (treat as success - goal achieved)
        if (has_post_thumbnail($post_id)) {
            wp_send_json_success(['message' => 'Already has featured image', 'skipped' => true]);
        }

        // Find first usable image with debug info
        $result = $this->find_first_media_image($post->post_content, true);

        // Check if we got an attachment ID (success) or debug info (failure)
        if (is_array($result) && isset($result['id'])) {
            $attachment_id = $result['id'];
            set_post_thumbnail($post_id, $attachment_id);
            wp_send_json_success([
                'message' => 'Featured image set',
                'attachment_id' => $attachment_id,
                'method' => $result['method']
            ]);
        } else {
            // Return detailed error message
            $reason = is_array($result) && isset($result['reason']) ? $result['reason'] : 'No usable image found';
            wp_send_json_error(['message' => $reason]);
        }
    }

    /**
     * Find first image in content that exists in media library
     *
     * @param string $content Post content
     * @param bool $return_debug Return debug info instead of just ID
     * @return int|array|false Attachment ID, debug array, or false
     */
    private function find_first_media_image($content, $return_debug = false) {
        $debug_info = [
            'method' => null,
            'found_ids' => [],
            'found_urls' => [],
            'reason' => 'No images found in content',
        ];

        // Method 1: Try to find wp-image-{ID} class (Gutenberg/Block Editor)
        if (preg_match_all('/wp-image-(\d+)/i', $content, $class_matches)) {
            $debug_info['found_ids'] = array_merge($debug_info['found_ids'], $class_matches[1]);
            foreach ($class_matches[1] as $potential_id) {
                $potential_id = intval($potential_id);
                $post_type = get_post_type($potential_id);
                if ($potential_id && $post_type === 'attachment') {
                    if ($return_debug) {
                        return ['id' => $potential_id, 'method' => 'wp-image class'];
                    }
                    return $potential_id;
                }
                $debug_info['reason'] = "Found wp-image-{$potential_id} but post type is '{$post_type}' (not attachment)";
            }
        }

        // Method 2: Try data-id attribute (some blocks use this)
        if (preg_match_all('/data-id=["\'](\d+)["\']/i', $content, $data_matches)) {
            $debug_info['found_ids'] = array_merge($debug_info['found_ids'], $data_matches[1]);
            foreach ($data_matches[1] as $potential_id) {
                $potential_id = intval($potential_id);
                $post_type = get_post_type($potential_id);
                if ($potential_id && $post_type === 'attachment') {
                    if ($return_debug) {
                        return ['id' => $potential_id, 'method' => 'data-id attribute'];
                    }
                    return $potential_id;
                }
                $debug_info['reason'] = "Found data-id={$potential_id} but post type is '{$post_type}' (not attachment)";
            }
        }

        // Method 3: Parse image src URLs
        preg_match_all('/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]*>/i', $content, $matches);

        if (empty($matches[1]) || !is_array($matches[1])) {
            if ($return_debug) {
                return $debug_info;
            }
            return false;
        }

        $debug_info['found_urls'] = $matches[1];

        foreach ($matches[1] as $url) {
            // Skip external images and data URIs
            if (strpos($url, 'data:') === 0) {
                continue;
            }

            // Try direct lookup
            $att_id = attachment_url_to_postid($url);

            // If not found, try removing size suffix (-300x200, -1024x768, etc.)
            if (!$att_id) {
                $url_without_size = preg_replace('/-\d+x\d+(\.[a-z]{3,4})$/i', '$1', $url);
                if ($url_without_size !== $url) {
                    $att_id = attachment_url_to_postid($url_without_size);
                }
            }

            // If still not found, try removing scaled suffix (-scaled)
            if (!$att_id) {
                $url_without_scaled = preg_replace('/-scaled(\.[a-z]{3,4})$/i', '$1', $url);
                if ($url_without_scaled !== $url) {
                    $att_id = attachment_url_to_postid($url_without_scaled);
                }
            }

            if ($att_id) {
                if ($return_debug) {
                    return ['id' => $att_id, 'method' => 'URL lookup'];
                }
                return $att_id;
            }
        }

        $debug_info['reason'] = 'Images found but none matched media library (URLs may be external or attachment deleted)';

        if ($return_debug) {
            return $debug_info;
        }
        return false;
    }
}

// Initialize and register with data system
$switchboard_instance = new SwitchboardAutoFeaturedImage();
Switchboard_Data_Registry::get_instance()->auto_register($switchboard_instance, __FILE__);
