<?php

namespace Mamba\Modules\Media\Services;

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

final class ImageCompressor {
    
    private const COMPRESSION_META_KEY = '_mamba_compression_quality';
    
    public function register(): void {
        // Feature Gating: Image Compression is a Premium feature
        if (!get_option('mamba_enable_image_compression', 0) || !function_exists('mamba_fs') || !mamba_fs()->can_use_premium_code__premium_only()) {
            return;
        }
        
        add_filter('wp_generate_attachment_metadata', [$this, 'processNewUpload'], 9, 2);
        add_filter('wp_get_attachment_image_attributes', [$this, 'addCompressionInfo'], 10, 3);
        
        // Process images when they're linked to products
        add_action('added_post_meta', [$this, 'processLinkedImage'], 10, 4);
        add_action('updated_post_meta', [$this, 'processLinkedImage'], 10, 4);
    }
    
    public function processNewUpload(array $metadata, int $attachmentId): array {
        if (!$this->shouldProcessAttachment($attachmentId)) {
            return $metadata;
        }
        
        $quality = (int) get_option('mamba_compression_quality', 85);
        
        foreach ($metadata['sizes'] ?? [] as $sizeName => $sizeData) {
            $this->processImageSize($attachmentId, $sizeName, $sizeData, $quality);
        }
        
        if (get_option('mamba_compress_full_size', 0)) {
            $this->processImageSize($attachmentId, 'full', $metadata, $quality);
        }
        
        return $metadata;
    }
    
    public function processImageSize(int $attachmentId, string $sizeName, array $_sizeData, int $quality): bool {
        $filePath = $this->getImagePath($attachmentId, $sizeName);
        if (!$filePath || !file_exists($filePath)) {
            return false;
        }
        
        // Check if already compressed and has backup
        $compressionData = get_post_meta($attachmentId, self::COMPRESSION_META_KEY, true) ?: [];
        $existingBackup = $compressionData[$sizeName]['backup_path'] ?? null;
        
        // Only create backup if we don't have one
        if (!$existingBackup || !file_exists($existingBackup)) {
            $backupPath = $this->createBackup($filePath, $attachmentId, $sizeName);
            if (!$backupPath) {
                return false;
            }
        } else {
            $backupPath = $existingBackup;
        }
        
        // Get compression type
        $compressionType = get_option('mamba_compression_type', 'lossy');
        
        $success = $this->compressFile($filePath, $quality, $compressionType);
        
        if ($success) {
            $this->storeCompressionInfo($attachmentId, $sizeName, $quality, $backupPath, $compressionType);
        } else {
            $this->restoreBackup($filePath, $backupPath);
        }
        
        return $success;
    }
    
    private function compressFile(string $filePath, int $quality, string $compressionType = 'lossy'): bool {
        // Validate and normalize the file path
        $filePath = wp_normalize_path($filePath);
        
        if (!file_exists($filePath) || !is_readable($filePath)) {
            return false;
        }
        
        $editor = wp_get_image_editor($filePath);
        
        if (is_wp_error($editor)) {
            return false;
        }
        
        // For lossless compression, use higher quality and preserve metadata
        if ($compressionType === 'lossless') {
            $quality = 100;
        }
        
        // Set the quality directly on the editor
        $editor->set_quality($quality);
        
        // Save without specifying the path (overwrites original)
        $result = $editor->save($filePath);
        
        return !is_wp_error($result);
    }
    
    private function createBackup(string $filePath, int $attachmentId, string $sizeName): ?string {
        $uploadDir = wp_upload_dir();
        $backupDir = $uploadDir['basedir'] . '/mamba-backups/compression/' . $attachmentId;
        
        // Ensure backup directory exists
        if (!wp_mkdir_p($backupDir)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba: Failed to create backup directory: {$backupDir}");
            }
            return null;
        }
        
        // Create a unique backup filename
        $timestamp = time();
        $backupPath = $backupDir . '/' . $sizeName . '_original_' . $timestamp . '_' . basename($filePath);
        
        // Verify source file exists and is readable
        if (!file_exists($filePath) || !is_readable($filePath)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba: Source file not accessible for backup: {$filePath}");
            }
            return null;
        }
        
        // Create backup with error handling
        if (!copy($filePath, $backupPath)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba: Failed to create backup: {$filePath} -> {$backupPath}");
            }
            return null;
        }
        
        // Verify backup was created successfully
        if (!file_exists($backupPath) || filesize($backupPath) === 0) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba: Backup file verification failed: {$backupPath}");
            }
            @unlink($backupPath); // Clean up failed backup
            return null;
        }
        
        return $backupPath;
    }
    
    private function restoreBackup(string $filePath, string $backupPath): bool {
        if (!file_exists($backupPath)) {
            return false;
        }
        
        return copy($backupPath, $filePath);
    }
    
    private function storeCompressionInfo(int $attachmentId, string $sizeName, int $quality, string $backupPath, string $compressionType = 'lossy'): void {
        $compressionData = get_post_meta($attachmentId, self::COMPRESSION_META_KEY, true) ?: [];
        $compressionData[$sizeName] = [
            'quality' => $quality,
            'backup_path' => $backupPath,
            'compression_type' => $compressionType,
            'compressed_at' => current_time('mysql')
        ];
        
        update_post_meta($attachmentId, self::COMPRESSION_META_KEY, $compressionData);
        wp_cache_delete('mamba_compression_stats', 'mamba_media');
    }
    
    private function getImagePath(int $attachmentId, string $sizeName): ?string {
        if ($sizeName === 'full') {
            $filePath = get_attached_file($attachmentId);
            return $filePath ? wp_normalize_path($filePath) : null;
        }

        $metadata = wp_get_attachment_metadata($attachmentId);
        if (!is_array($metadata) || !isset($metadata['file'], $metadata['sizes'][$sizeName]['file'])) {
            return null;
        }

        $uploadDir = wp_upload_dir();
        if (is_wp_error($uploadDir) || !isset($uploadDir['basedir'])) {
            return null;
        }
        
        $path = trailingslashit($uploadDir['basedir'])
            . dirname($metadata['file']) . '/'
            . $metadata['sizes'][$sizeName]['file'];
            
        return wp_normalize_path($path);
    }
    
    private function getMimeType(string $filePath): string {
        $fileType = wp_check_filetype($filePath);
        return $fileType['type'] ?: 'image/jpeg';
    }
    
    private function shouldProcessAttachment(int $attachmentId): bool {
        $mimeType = get_post_mime_type($attachmentId);
        if (!in_array($mimeType, ['image/jpeg', 'image/png'], true)) {
            return false;
        }
        
        $compressionData = get_post_meta($attachmentId, self::COMPRESSION_META_KEY, true);
        if (!empty($compressionData)) {
            return false;
        }
        
        return $this->isWooCommerceImage($attachmentId);
    }
    
    /**
     * Process image when it's linked to a product
     */
    public function processLinkedImage(int $metaId, int $postId, string $metaKey, $metaValue): void {
        // Check if this is a product linking to an image
        if ($metaKey === '_thumbnail_id' || $metaKey === '_product_image_gallery') {
            $attachmentId = (int) $metaValue;
            
            // For gallery, check each image
            if ($metaKey === '_product_image_gallery' && is_string($metaValue)) {
                $galleryIds = array_filter(array_map('intval', explode(',', $metaValue)));
                foreach ($galleryIds as $galleryId) {
                    $this->processImageIfNeeded($galleryId);
                }
            } else {
                $this->processImageIfNeeded($attachmentId);
            }
        }
    }
    
    /**
     * Process image if it needs compression
     */
    private function processImageIfNeeded(int $attachmentId): void {
        if (!$this->shouldProcessAttachment($attachmentId)) {
            return;
        }
        
        $metadata = wp_get_attachment_metadata($attachmentId);
        if (!$metadata) {
            return;
        }
        
        $quality = (int) get_option('mamba_compression_quality', 85);
        
        foreach ($metadata['sizes'] ?? [] as $sizeName => $sizeData) {
            $this->processImageSize($attachmentId, $sizeName, $sizeData, $quality);
        }
        
        if (get_option('mamba_compress_full_size', 0)) {
            $this->processImageSize($attachmentId, 'full', $metadata, $quality);
        }
    }
    
    private function isWooCommerceImage(int $attachmentId): bool {
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
        $products = get_posts([
            'post_type' => 'product',
            'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
                [
                    'key' => '_thumbnail_id',
                    'value' => $attachmentId
                ]
            ],
            'posts_per_page' => 1
        ]);
        
        if (!empty($products)) {
            return true;
        }
        
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
        $products = get_posts([
            'post_type' => 'product',
            'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
                [
                    'key' => '_product_image_gallery',
                    'value' => $attachmentId,
                    'compare' => 'LIKE'
                ]
            ],
            'posts_per_page' => 1
        ]);
        
        if (!empty($products)) {
            return true;
        }
        
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
        $variations = get_posts([
            'post_type' => 'product_variation',
            'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
                [
                    'key' => '_thumbnail_id',
                    'value' => $attachmentId
                ]
            ],
            'posts_per_page' => 1
        ]);
        
        return !empty($variations);
    }
    
    public function addCompressionInfo(array $attr, $attachment, $size): array {
        if (!is_object($attachment)) {
            return $attr;
        }
        
        $compressionData = get_post_meta($attachment->ID, self::COMPRESSION_META_KEY, true);
        if (!empty($compressionData)) {
            $attr['data-mamba-compressed'] = 'true';
        }
        
        return $attr;
    }
    
    public function revertCompression(int $attachmentId): bool {
        $compressionData = get_post_meta($attachmentId, self::COMPRESSION_META_KEY, true);
        if (empty($compressionData)) {
            return false;
        }
        
        $success = true;
        $backupDir = null;
        $revertedCount = 0;
        
        foreach ($compressionData as $sizeName => $data) {
            $filePath = $this->getImagePath($attachmentId, $sizeName);
            $backupPath = $data['backup_path'] ?? '';
            
            if ($filePath && $backupPath && file_exists($backupPath)) {
                if ($this->restoreBackup($filePath, $backupPath)) {
                    $revertedCount++;
                } else {
                    $success = false;
                    if (defined('WP_DEBUG') && WP_DEBUG) {
                        error_log("Mamba: Failed to restore backup for {$sizeName}: {$backupPath}");
                    }
                }
                
                // Track backup directory for cleanup
                if ($backupDir === null) {
                    $backupDir = dirname($backupPath);
                }
            } else {
                // Backup doesn't exist - this is a limitation we can't overcome
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    error_log("Mamba: Backup not found for {$sizeName}, cannot revert: {$backupPath}");
                }
                $success = false;
            }
        }
        
        if ($success || $revertedCount > 0) {
            // Remove the compression metadata even if some files couldn't be reverted
            delete_post_meta($attachmentId, self::COMPRESSION_META_KEY);
            wp_cache_delete('mamba_compression_stats', 'mamba_media');
            
            // Clean up compression backup directory
            if ($backupDir && is_dir($backupDir)) {
                try {
                    // Only remove files listed in our meta (compression backups)
                    foreach ($compressionData as $sizeName => $data) {
                        $backupPath = $data['backup_path'] ?? '';
                        if ($backupPath && file_exists($backupPath)) {
                            @unlink($backupPath);
                        }
                    }
                    
                    // Remove directory if empty
                    $remainingFiles = glob($backupDir . '/*');
                    if (empty($remainingFiles)) {
                        @rmdir($backupDir);
                    }
                } catch (\Exception $e) {
                    // Suppress cleanup failures - not critical
                    if (defined('WP_DEBUG') && WP_DEBUG) {
                        error_log("Mamba: Cleanup error during revert: " . $e->getMessage());
                    }
                }
            }
        }
        
        return $success;
    }
    
    public function getCompressionStats(): array {
        $cached = wp_cache_get('mamba_compression_stats', 'mamba_media');
        if (false !== $cached) {
            return $cached;
        }
        
        global $wpdb;
        
        // 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::COMPRESSION_META_KEY
        ));
        
        // 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/%'
        ));
        
        $stats = [
            'compressed' => (int) $compressedCount,
            'total' => (int) $totalImages,
            'percentage' => $totalImages > 0 ? round(($compressedCount / $totalImages) * 100, 1) : 0
        ];
        
        wp_cache_set('mamba_compression_stats', $stats, 'mamba_media', 3600);
        return $stats;
    }
}
