<?php
namespace Mamba\Modules\Media\Services;

use Mamba\Support\SavingsTracker;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

final class BulkOptimizer {
    
    public const BATCH_SIZE = 3;
    private const PROCESSING_TIMEOUT = 30;
    private const MEMORY_LIMIT = '256M';
    private const META_COMPRESSION = '_mamba_compression_quality';
    private const META_WEBP = '_mamba_webp_conversion';
    private const META_AVIF = '_mamba_avif_conversion';
    
    public function __construct() {}
    
    /**
     * Register AJAX handlers
     */
    public function register(): void {
        add_action('wp_ajax_mamba_bulk_compress', [$this, 'handleBulkCompress']);
        add_action('wp_ajax_mamba_bulk_webp', [$this, 'handleBulkWebP']);
        add_action('wp_ajax_mamba_bulk_avif', [$this, 'handleBulkAvif']);
        add_action('wp_ajax_mamba_bulk_revert', [$this, 'handleBulkRevert']);
        add_action('wp_ajax_mamba_get_optimization_stats', [$this, 'handleGetStats']);
    }
    
    /**
     * Handle bulk compression AJAX request
     */
    public function handleBulkCompress(): void {
        try {
            // Debug logging
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba Bulk Compress: Starting request');
            }
            
            check_ajax_referer('mamba_bulk_optimize', 'nonce');
            
            if (!current_user_can('manage_options')) {
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    error_log('Mamba Bulk Compress: Permission denied');
                }
                wp_send_json_error('Insufficient permissions');
            }
            
            // Performance optimizations
            $this->optimizeForBulkProcessing();
            
            $cursor = (int) wp_unslash($_POST['cursor'] ?? 0);
            $batchSize = (int) wp_unslash($_POST['batch_size'] ?? self::BATCH_SIZE);
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba Bulk Compress: Processing cursor={$cursor}, batchSize={$batchSize}");
            }
            
            $images = $this->getUnoptimizedImagesAfter($cursor, $batchSize);
            $imageCount = count($images);
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba Bulk Compress: Found {$imageCount} images to process");
            }
            
            $results = [];
            $lastId = $cursor;
            $processedCount = 0;
            
            foreach ($images as $image) {
                try {
                    // Clear memory more frequently for better performance
                    if ($processedCount % 3 === 0) {
                        $this->clearMemory();
                    }
                    
                    $success = $this->compressImage($image->ID);
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => $success
                    ];
                    if ($image->ID > $lastId) {
                        $lastId = $image->ID;
                    }
                    $processedCount++;
                    
                    if ($processedCount % 3 === 0) {
                        if (defined('WP_DEBUG') && WP_DEBUG) {
                            error_log("Mamba Bulk Compress: Processed {$processedCount}/{$imageCount} images");
                        }
                    }
                } catch (\Exception $e) {
                    if (defined('WP_DEBUG') && WP_DEBUG) {
                        error_log('Mamba Bulk Compress: Error processing image ' . $image->ID . ': ' . $e->getMessage());
                    }
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => false,
                        'error' => $e->getMessage()
                    ];
                }
            }
            
            $hasMore = count($images) === $batchSize;
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba Bulk Compress: Completed batch. Processed={$processedCount}, HasMore={$hasMore}, LastId={$lastId}");
            }
            
            wp_send_json_success([
                'results' => $results,
                'has_more' => $hasMore,
                'cursor' => $lastId,
                'memory_usage' => $this->getMemoryUsage()
            ]);
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba Bulk Compress: Fatal error: ' . $e->getMessage());
            }
            wp_send_json_error('Processing error: ' . $e->getMessage());
        }
    }
    
    /**
     * Handle bulk WebP conversion AJAX request
     */
    public function handleBulkWebP(): void {
        try {
            // Debug logging
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba Bulk WebP: Starting request');
            }
            
            check_ajax_referer('mamba_bulk_optimize', 'nonce');
            
            if (!current_user_can('manage_options')) {
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    error_log('Mamba Bulk WebP: Permission denied');
                }
                wp_send_json_error('Insufficient permissions');
            }
            
            // Bail out early if the stack can't write WebP
            if (!function_exists('wp_image_editor_supports') ||
                !wp_image_editor_supports(['mime_type' => 'image/webp'])) {
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    error_log('Mamba Bulk WebP: WebP not supported on server');
                }
                wp_send_json_error('WebP not supported on this server (GD/Imagick).');
            }
            
            // Performance optimizations
            $this->optimizeForBulkProcessing();
            
            // Ensure .htaccess rules are in place for Next-Gen serving
            $htaccessManager = new \Mamba\Modules\Media\Services\HtaccessManager();
            $serverInfo = $htaccessManager->getServerInfo();
            if ($htaccessManager->isSupported() && $serverInfo['is_apache_compatible'] && !$htaccessManager->hasNextGenRules()) {
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    error_log('Mamba Bulk WebP: Creating missing .htaccess rules');
                }
                $htaccessManager->addNextGenRules();
            }
            
            $cursor = (int) wp_unslash($_POST['cursor'] ?? 0);
            $batchSize = (int) wp_unslash($_POST['batch_size'] ?? self::BATCH_SIZE);
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba Bulk WebP: Processing cursor={$cursor}, batchSize={$batchSize}");
            }
            
            $images = $this->getUnconvertedImagesAfter('webp', $cursor, $batchSize);
            $imageCount = count($images);
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba Bulk WebP: Found {$imageCount} images to process");
            }
            
            $results = [];
            $lastId = $cursor;
            $processedCount = 0;
            
            foreach ($images as $image) {
                try {
                    // Clear memory more frequently for better performance
                    if ($processedCount % 3 === 0) {
                        $this->clearMemory();
                    }
                    
                    $success = $this->convertToFormat($image->ID, 'webp');
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => $success
                    ];
                    
                    // Log conversion
                    if (class_exists('\Mamba\Support\Logger')) {
                        \Mamba\Support\Logger::info('WebP conversion: ' . ($success ? 'success' : 'failed'), [
                            'attachment_id' => $image->ID,
                            'title' => $image->post_title
                        ]);
                    }
                    if ($image->ID > $lastId) {
                        $lastId = $image->ID;
                    }
                    $processedCount++;
                    
                    if ($processedCount % 3 === 0) {
                        if (defined('WP_DEBUG') && WP_DEBUG) {
                            error_log("Mamba Bulk WebP: Processed {$processedCount}/{$imageCount} images");
                        }
                    }
                } catch (\Exception $e) {
                    if (defined('WP_DEBUG') && WP_DEBUG) {
                        error_log('Mamba Bulk WebP: Error processing image ' . $image->ID . ': ' . $e->getMessage());
                    }
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => false,
                        'error' => $e->getMessage()
                    ];
                }
            }
            
            $hasMore = count($images) === $batchSize;
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba Bulk WebP: Completed batch. Processed={$processedCount}, HasMore={$hasMore}, LastId={$lastId}");
            }
            
            wp_send_json_success([
                'results' => $results,
                'has_more' => $hasMore,
                'cursor' => $lastId,
                'memory_usage' => $this->getMemoryUsage()
            ]);
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba Bulk WebP: Fatal error: ' . $e->getMessage());
            }
            wp_send_json_error('Processing error: ' . $e->getMessage());
        }
    }

    /**
     * Handle bulk AVIF conversion AJAX request
     */
    public function handleBulkAvif(): void {
        try {
            // Debug logging
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba Bulk AVIF: Starting request');
            }
            
            check_ajax_referer('mamba_bulk_optimize', 'nonce');
            
            if (!current_user_can('manage_options')) {
                wp_send_json_error('Insufficient permissions');
            }
            
            // Bail out early if the stack can't write AVIF
            if (!function_exists('wp_image_editor_supports') ||
                !wp_image_editor_supports(['mime_type' => 'image/avif'])) {
                wp_send_json_error('AVIF not supported on this server (GD/Imagick).');
            }
            
            // Performance optimizations
            $this->optimizeForBulkProcessing();
            
            // Ensure .htaccess rules are in place for Next-Gen serving
            $htaccessManager = new \Mamba\Modules\Media\Services\HtaccessManager();
            $serverInfo = $htaccessManager->getServerInfo();
            if ($htaccessManager->isSupported() && $serverInfo['is_apache_compatible'] && !$htaccessManager->hasNextGenRules()) {
                $htaccessManager->addNextGenRules();
            }
            
            $cursor = (int) wp_unslash($_POST['cursor'] ?? 0);
            $batchSize = (int) wp_unslash($_POST['batch_size'] ?? self::BATCH_SIZE);
            
            $images = $this->getUnconvertedImagesAfter('avif', $cursor, $batchSize);
            $imageCount = count($images);
            
            $results = [];
            $lastId = $cursor;
            $processedCount = 0;
            
            foreach ($images as $image) {
                try {
                    if ($processedCount % 3 === 0) {
                        $this->clearMemory();
                    }
                    
                    $success = $this->convertToFormat($image->ID, 'avif');
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => $success
                    ];
                    
                    // Log conversion
                    if (class_exists('\Mamba\Support\Logger')) {
                        \Mamba\Support\Logger::info('AVIF conversion: ' . ($success ? 'success' : 'failed'), [
                            'attachment_id' => $image->ID,
                            'title' => $image->post_title
                        ]);
                    }
                    if ($image->ID > $lastId) {
                        $lastId = $image->ID;
                    }
                    $processedCount++;
                } catch (\Exception $e) {
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => false,
                        'error' => $e->getMessage()
                    ];
                }
            }
            
            $hasMore = count($images) === $batchSize;
            
            wp_send_json_success([
                'results' => $results,
                'has_more' => $hasMore,
                'cursor' => $lastId,
                'memory_usage' => $this->getMemoryUsage()
            ]);
        } catch (\Exception $e) {
            wp_send_json_error('Processing error: ' . $e->getMessage());
        }
    }
    
    /**
     * Handle bulk revert AJAX request
     */
    public function handleBulkRevert(): void {
        try {
            check_ajax_referer('mamba_bulk_optimize', 'nonce');
            
            if (!current_user_can('manage_options')) {
                wp_send_json_error('Insufficient permissions');
            }
            
            $type = sanitize_text_field(wp_unslash($_POST['type'] ?? ''));
            if (!in_array($type, ['compression', 'webp', 'avif'])) {
                wp_send_json_error('Invalid optimization type');
            }
            
            $cursor = (int) wp_unslash($_POST['cursor'] ?? 0);
            $batchSize = (int) wp_unslash($_POST['batch_size'] ?? self::BATCH_SIZE);
            
            // Set timeout for long operations
            set_time_limit(self::PROCESSING_TIMEOUT);
            
            $images = $this->getOptimizedImagesAfter($type, $cursor, $batchSize);
            $results = [];
            $lastId = $cursor;
            
            foreach ($images as $image) {
                try {
                    $success = $this->revertOptimization($image->ID, $type);
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => $success
                    ];
                    if ($image->ID > $lastId) {
                        $lastId = $image->ID;
                    }
                } catch (\Exception $e) {
                    $results[] = [
                        'id' => $image->ID,
                        'title' => $image->post_title,
                        'success' => false,
                        'error' => $e->getMessage()
                    ];
                }
            }
            
            $hasMore = count($images) === $batchSize;
            
            // Reset image savings stats when reverting is complete (no more images to process)
            if (!$hasMore) {
                SavingsTracker::resetImageSavings();
            }
            
            wp_send_json_success([
                'results' => $results,
                'has_more' => $hasMore,
                'cursor' => $lastId
            ]);
        } catch (\Exception $e) {
            wp_send_json_error('Processing error: ' . $e->getMessage());
        }
    }
    
    /**
     * Handle get stats AJAX request
     */
    public function handleGetStats(): void {
        check_ajax_referer('mamba_bulk_optimize', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Insufficient permissions');
        }
        
        $compressor = new ImageCompressor();
        $webpConverter = new WebPConverter();
        $avifConverter = new AvifConverter();
        
        wp_send_json_success([
            'compression' => $compressor->getCompressionStats(),
            'webp' => $webpConverter->getWebPStats(),
            'avif' => $avifConverter->getAvifStats()
        ]);
    }
    
    /**
     * Get unoptimized images for compression
     */
    private function getUnoptimizedImagesAfter(int $cursor, int $limit): array {
        global $wpdb;
        $meta_key = self::META_COMPRESSION;

        $sql = "
        SELECT p.ID, p.post_title
        FROM {$wpdb->posts} p
        LEFT JOIN {$wpdb->postmeta} cm 
               ON cm.post_id = p.ID AND cm.meta_key = %s
        WHERE p.post_type = 'attachment'
          AND p.post_mime_type IN ('image/jpeg', 'image/png')
          AND cm.meta_id IS NULL
          AND p.ID > %d
        ORDER BY p.ID
        LIMIT %d";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_results($wpdb->prepare($sql, $meta_key, $cursor, $limit));
    }
    
    /**
     * Get unconverted images for WebP/AVIF
     */
    private function getUnconvertedImagesAfter(string $format, int $cursor, int $limit): array {
        global $wpdb;
        $meta_key = ($format === 'avif') ? self::META_AVIF : self::META_WEBP;

        $sql = "
        SELECT p.ID, p.post_title
        FROM {$wpdb->posts} p
        LEFT JOIN {$wpdb->postmeta} cm 
               ON cm.post_id = p.ID AND cm.meta_key = %s
        WHERE p.post_type = 'attachment'
          AND p.post_mime_type IN ('image/jpeg', 'image/png')
          AND cm.meta_id IS NULL
          AND p.ID > %d
        ORDER BY p.ID
        LIMIT %d";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_results($wpdb->prepare($sql, $meta_key, $cursor, $limit));
    }
    
    /**
     * Get optimized images for revert
     */
    private function getOptimizedImagesAfter(string $type, int $cursor, int $limit): array {
        global $wpdb;
        
        $metaKey = self::META_COMPRESSION;
        if ($type === 'webp') $metaKey = self::META_WEBP;
        if ($type === 'avif') $metaKey = self::META_AVIF;
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_results($wpdb->prepare(
            "SELECT p.ID, p.post_title 
             FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = %s
             WHERE p.post_type = 'attachment'
             AND p.ID > %d
             ORDER BY p.ID
             LIMIT %d",
            $metaKey,
            $cursor,
            $limit
        ));
    }
    
    /**
     * Compress a single image
     */
    private function compressImage(int $attachmentId): bool {
        $metadata = wp_get_attachment_metadata($attachmentId);
        if (!$metadata) {
            return false;
        }
        
        $mime = get_post_mime_type($attachmentId);
        if (!in_array($mime, ['image/jpeg', 'image/png'], true)) {
            return false;
        }
        
        $compressor = new ImageCompressor();
        $quality = (int) get_option('mamba_compression_quality', 85);
        $processedCount = 0;
        
        // Process generated sizes
        foreach ($metadata['sizes'] ?? [] as $sizeName => $sizeData) {
            if ($compressor->processImageSize($attachmentId, $sizeName, $sizeData, $quality)) {
                $processedCount++;
            }
        }
        
        // Process full size if enabled
        if (get_option('mamba_compress_full_size', 0)) {
            if ($compressor->processImageSize($attachmentId, 'full', $metadata, $quality)) {
                $processedCount++;
            }
        }
        
        // Return true if at least one size was processed successfully
        return $processedCount > 0;
    }
    
    /**
     * Convert a single image to WebP or AVIF
     */
    private function convertToFormat(int $attachmentId, string $format): bool {
        // Check support
        if (!function_exists('wp_image_editor_supports') ||
            !wp_image_editor_supports(['mime_type' => "image/{$format}"])) {
            return false;
        }
        
        $converter = ($format === 'avif') ? new AvifConverter() : new WebPConverter();
        
        $metadata = wp_get_attachment_metadata($attachmentId);
        if (!$metadata) {
            return false;
        }
        
        $quality_opt = ($format === 'avif') ? 'mamba_avif_quality' : 'mamba_webp_quality';
        $full_size_opt = ($format === 'avif') ? 'mamba_convert_full_size_avif' : 'mamba_convert_full_size';
        $default_quality = ($format === 'avif') ? 65 : 85;

        $quality = (int) get_option($quality_opt, $default_quality);
        $processedCount = 0;
        
        // Process generated sizes
        foreach ($metadata['sizes'] ?? [] as $sizeName => $sizeData) {
            if ($converter->processImageSize($attachmentId, $sizeName, $sizeData, $quality)) {
                $processedCount++;
            }
        }
        
        // Process full size if enabled
        if (get_option($full_size_opt, 0)) {
            if ($converter->processImageSize($attachmentId, 'full', $metadata, $quality)) {
                $processedCount++;
            }
        }
        
        return $processedCount > 0;
    }
    
    /**
     * Revert optimization for a single image
     */
    private function revertOptimization(int $attachmentId, string $type): bool {
        if ($type === 'webp') {
            $webpConverter = new WebPConverter();
            return $webpConverter->revertWebP($attachmentId);
        } elseif ($type === 'avif') {
            $avifConverter = new AvifConverter();
            return $avifConverter->revertAvif($attachmentId);
        } else {
            $compressor = new ImageCompressor();
            return $compressor->revertCompression($attachmentId);
        }
    }
    
    /**
     * Get total counts for progress tracking
     */
    public function getTotalCounts(): array {
        global $wpdb;
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $totalImages = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->posts} 
             WHERE post_type = 'attachment' 
             AND post_mime_type LIKE %s",
            'image/%'
        ));
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $eligibleImages = $wpdb->get_var("
            SELECT COUNT(*) FROM {$wpdb->posts}
            WHERE post_type = 'attachment'
              AND post_mime_type IN ('image/jpeg', 'image/png')
        ");
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $compressedCount = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(DISTINCT post_id) FROM {$wpdb->postmeta} 
             WHERE meta_key = %s",
            self::META_COMPRESSION
        ));
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $webpCount = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(DISTINCT post_id) FROM {$wpdb->postmeta} 
             WHERE meta_key = %s",
            self::META_WEBP
        ));
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $avifCount = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(DISTINCT post_id) FROM {$wpdb->postmeta} 
             WHERE meta_key = %s",
            self::META_AVIF
        ));
        
        return [
            'total' => (int) $totalImages,
            'eligible' => (int) $eligibleImages,
            'compressed' => (int) $compressedCount,
            'webp' => (int) $webpCount,
            'avif' => (int) $avifCount
        ];
    }
    
    /**
     * Optimize server settings for bulk processing
     */
    private function optimizeForBulkProcessing(): void {
        // Increase time limit
        set_time_limit(self::PROCESSING_TIMEOUT);
        
        // Increase memory limit if possible
        if (function_exists('ini_set')) {
            $currentLimit = ini_get('memory_limit');
            if ($this->parseMemoryLimit($currentLimit) < $this->parseMemoryLimit(self::MEMORY_LIMIT)) {
                @ini_set('memory_limit', self::MEMORY_LIMIT);
            }
        }
        
        // Clear accumulated queries to save memory during bulk operations
        global $wpdb;
        $wpdb->queries = [];
    }
    
    /**
     * Clear memory and WordPress caches
     */
    private function clearMemory(): void {
        // Clear WordPress object cache
        if (function_exists('wp_cache_flush')) {
            wp_cache_flush();
        }
        
        // Clear any persistent caches
        if (function_exists('wp_cache_delete_multiple')) {
            wp_cache_delete_multiple([
                'post_meta',
                'post_data',
                'attachment_meta'
            ]);
        }
        
        // Force garbage collection
        if (function_exists('gc_collect_cycles')) {
            gc_collect_cycles();
        }
    }
    
    /**
     * Get current memory usage info
     */
    private function getMemoryUsage(): array {
        return [
            'current' => $this->formatBytes(memory_get_usage(true)),
            'peak' => $this->formatBytes(memory_get_peak_usage(true)),
            'limit' => ini_get('memory_limit')
        ];
    }
    
    /**
     * Parse memory limit string to bytes
     */
    private function parseMemoryLimit(string $limit): int {
        $limit = trim($limit);
        $last = strtolower(substr($limit, -1));
        $number = (int) substr($limit, 0, -1);
        
        switch ($last) {
            case 'g': return $number * 1024 * 1024 * 1024;
            case 'm': return $number * 1024 * 1024;
            case 'k': return $number * 1024;
            default: return (int) $limit;
        }
    }
    
    /**
     * Format bytes to human readable string
     */
    private function formatBytes(int $bytes): string {
        $units = ['B', 'KB', 'MB', 'GB'];
        $factor = floor((strlen($bytes) - 1) / 3);
        return sprintf("%.2f %s", $bytes / pow(1024, $factor), $units[$factor]);
    }
}
