<?php
/**
 * WEBP Image Converter
 *
 * @package PackshotPhotoAI
 */

namespace PackshotPhotoAI\Core;

defined('ABSPATH') || exit;

/**
 * Handles WEBP image conversion
 */
class WebPConverter {

    /**
     * Default quality for WEBP conversion
     */
    private const DEFAULT_QUALITY = 85;

    /**
     * Convert attachment via AJAX
     */
    public function ajax_convert(): void {
        $post_id = isset($_POST['id']) ? absint($_POST['id']) : 0;
        if (!$post_id) {
            wp_send_json_error(['success' => false, 'message' => __('Invalid ID', 'packshotphoto-ai')], 400);
        }

        // Verify nonce
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!\wp_verify_nonce($nonce, 'packshotphoto_edit_' . $post_id)) {
            \wp_send_json_error(['success' => false, 'message' => __('Security error', 'packshotphoto-ai')], 403);
        }

        // Check capability
        if (!\current_user_can('edit_post', $post_id)) {
            \wp_send_json_error(['success' => false, 'message' => __('Permission denied', 'packshotphoto-ai')], 403);
        }

        // Sanitize post keys before logging
        $post_keys_log = isset($_POST) && is_array($_POST) ? array_map('sanitize_key', array_keys($_POST)) : [];
        Logger::info('WebPConverter: ajax_convert called', ['post_id' => $post_id, 'POST' => $post_keys_log]);

        // Check if convertible
        $mime_type = \get_post_mime_type($post_id);
        $file_path = \get_attached_file($post_id);
        
        Logger::info('WebPConverter: Starting conversion', [
            'post_id' => $post_id,
            'mime_type' => $mime_type,
            'file_path' => $file_path,
            'file_exists' => file_exists($file_path)
        ]);

        if (!in_array($mime_type, ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif'], true)) {
            \wp_send_json_error(['success' => false, 'message' => __('This format does not support WEBP conversion', 'packshotphoto-ai')]);
        }

        // Check GD/Imagick support
        if (!$this->can_convert()) {
            wp_send_json_error(['success' => false, 'message' => __('PHP WEBP support missing (GD or Imagick required)', 'packshotphoto-ai')]);
        }

        ob_start();
        $result = $this->convert($post_id, true); // Always regenerate metadata + thumbnails
        $ob_content = ob_get_clean();

        Logger::info('WebPConverter: convert() returned', ['post_id' => $post_id, 'result' => $result]);

        if ($ob_content) {
            Logger::warning('WebPConverter warning output caught', ['content' => $ob_content]);
        }

        if ($result['success']) {
            $payload = $result['data'] ?? [];
            if (isset($result['message'])) {
                $payload['message'] = $result['message'];
            }
            
            // Debug: Add current attachment metadata to response
            $debug_metadata = \wp_get_attachment_metadata($post_id);
            $payload['debug'] = [
                'metadata_width' => $debug_metadata['width'] ?? 'N/A',
                'metadata_height' => $debug_metadata['height'] ?? 'N/A',
                'metadata_file' => $debug_metadata['file'] ?? 'N/A',
                'metadata_sizes_count' => count($debug_metadata['sizes'] ?? []),
                'metadata_sizes' => $debug_metadata['sizes'] ?? [],
                'attached_file' => \get_attached_file($post_id),
                'attachment_url' => \wp_get_attachment_url($post_id),
                'mime_type' => \get_post_mime_type($post_id),
            ];
            
            Logger::info('WebPConverter: Full response payload', ['post_id' => $post_id, 'payload' => $payload]);
            
            \wp_send_json_success($payload);
        } else {
            Logger::error('WEBP conversion AJAX failure', ['id' => $post_id, 'result' => $result]);
            \wp_send_json_error($result);
        }
    }

    /**
     * Check if WEBP conversion is supported
     *
     * @return bool
     */
    public function can_convert(): bool {
        // Check Imagick first (better quality)
        if (extension_loaded('imagick')) {
            $formats = \Imagick::queryFormats('WEBP');
            if (!empty($formats)) {
                return true;
            }
        }

        // Fallback to GD
        if (function_exists('imagewebp')) {
            return true;
        }

        return false;
    }

    /**
     * Convert attachment to WEBP
     *
     * @param int  $post_id             Attachment ID
     * @param bool $regenerate_metadata Whether to regenerate thumbnails
     * @return array{success: bool, message: string, data?: array}
     */
    public function convert(int $post_id, bool $regenerate_metadata = false): array {
        Logger::info('WebPConverter: convert() started', ['post_id' => $post_id, 'regenerate_metadata' => $regenerate_metadata]);
        
        $file_path = \get_attached_file($post_id);
        
        if (!$file_path || !file_exists($file_path)) {
            // Recovery Attempt 1: Check if another format version (like WebP or AVIF or PNG/JPG) exists in the same folder
            if ($file_path) {
                $path_parts = pathinfo($file_path);
                $extensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'];
                foreach ($extensions as $ext) {
                    if (strtolower($path_parts['extension']) !== $ext) {
                        $test_path = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.' . $ext;
                        if (file_exists($test_path)) {
                            $file_path = $test_path;
                            Logger::info('WebPConverter: Recovered source file from alternative extension', ['post_id' => $post_id, 'file_path' => $file_path]);
                            break;
                        }
                    }
                }
            }
        }

        if (!$file_path || !file_exists($file_path)) {
            // Recovery Attempt 2: Recover from original backup in trash
            $backup_rel = \get_post_meta($post_id, '_pmm_original_backup', true);
            if ($backup_rel) {
                $upload_dir = \wp_upload_dir();
                $backup_path = $upload_dir['basedir'] . '/' . $backup_rel;
                if (file_exists($backup_path)) {
                    if (@copy($backup_path, $file_path)) {
                        Logger::info('WebPConverter: Recovered source file from backup trash', ['post_id' => $post_id, 'file_path' => $file_path]);
                    }
                }
            }
        }

        if (!$file_path || !file_exists($file_path)) {
            return [
                'success' => false,
                'message' => __('Source file does not exist', 'packshotphoto-ai'),
            ];
        }

        $path_info = pathinfo($file_path);
        $original_extension = $path_info['extension'];
        $original_filename = basename($file_path);

        if (!\get_post_meta($post_id, '_pmm_original_filename', true)) {
            \update_post_meta($post_id, '_pmm_original_filename', $original_filename);
        }
        
        // Skip if already WEBP (to avoid double conversion)
        if ('webp' === strtolower($path_info['extension'])) {
            $size = file_exists($file_path) ? filesize($file_path) : 0;
            return [
                'success' => true,
                'message' => __('File is already in WEBP format.', 'packshotphoto-ai'),
                'data'    => [
                    'url'            => \wp_get_attachment_url($post_id),
                    'path'           => $file_path,
                    'new_filename'   => basename($file_path),
                    'new_url'        => \wp_get_attachment_url($post_id),
                    'before_format'  => 'WEBP',
                    'after_format'   => 'WEBP',
                    'before_size'    => size_format($size),
                    'after_size'     => size_format($size),
                    'savings'        => 0,
                ],
            ];
        }

        $webp_path = $path_info['dirname'] . '/' . $path_info['filename'] . '.webp';

        // Convert using best available method
        $converted = $this->do_conversion($file_path, $webp_path);

        if (!$converted) {
            return [
                'success' => false,
                'message' => __('Conversion failed', 'packshotphoto-ai'),
            ];
        }

        // Verify WEBP was created and is valid
        if (!file_exists($webp_path) || filesize($webp_path) === 0) {
            wp_delete_file($webp_path);
            return [
                'success' => false,
                'message' => __('WEBP file is empty or was not created', 'packshotphoto-ai'),
            ];
        }

        // Get current metadata to know where thumbnails are stored
        $old_metadata = \wp_get_attachment_metadata($post_id);
        $upload_dir = \wp_upload_dir();
        
        // Calculate relative path for WEBP
        $relative_path = \_wp_relative_upload_path($webp_path);

        // Update attachment - point to new WEBP file
        \update_attached_file($post_id, $webp_path);
        
        \wp_update_post([
            'ID'             => $post_id,
            'post_mime_type' => 'image/webp',
            'guid'           => $upload_dir['baseurl'] . '/' . $relative_path,
        ]);

        // Delete old thumbnail files from disk (before we lose $file_path reference)
        $old_thumb_paths = [];
        if (!empty($old_metadata['sizes'])) {
            foreach ($old_metadata['sizes'] as $size_info) {
                if (!empty($size_info['file'])) {
                    $old_thumb_path = dirname($file_path) . '/' . $size_info['file'];
                    if (file_exists($old_thumb_path)) {
                        $old_thumb_paths[] = $old_thumb_path;
                    }
                }
            }
        }

        if ($regenerate_metadata) {
            // Delete old thumbnail files
            foreach ($old_thumb_paths as $old_thumb) {
                wp_delete_file($old_thumb);
            }
        }
        
        // Always generate WEBP thumbnails — WordPress needs them for media library
        // Keep old JPG thumbnails for backup/restore purposes
        $metadata = $this->generate_webp_metadata($post_id, $webp_path);
        
        if (!empty($metadata)) {
            \wp_update_attachment_metadata($post_id, $metadata);
        } else {
            // Fallback: update only main file info without thumbnail regeneration
            // Clear sizes to avoid broken thumbnail references
            $webp_image_data = @getimagesize($webp_path);
            if ($webp_image_data) {
                $fallback = [
                    'width'    => $webp_image_data[0],
                    'height'   => $webp_image_data[1],
                    'file'     => \_wp_relative_upload_path($webp_path),
                    'filesize' => filesize($webp_path),
                    'mime-type' => 'image/webp',
                    'sizes'    => [],
                ];
                \wp_update_attachment_metadata($post_id, $fallback);
            }
        }

        // Handle original file backup (use stored path since $file_path still points to original)
        $original_filesize = file_exists($file_path) ? filesize($file_path) : 0;
        $delete_mode = \get_option('packshotphoto_delete_mode', 'trash');
        
        if ('delete' === $delete_mode) {
            // Only delete if file still exists (might have been deleted during thumbnail cleanup)
            if (file_exists($file_path)) {
                wp_delete_file($file_path);
            }
        } elseif ('trash' === $delete_mode) {
            // Create unique backup filename with timestamp
            $timestamp     = time();
            $backup_name   = $path_info['filename'] . '-original-' . $timestamp . '.' . $original_extension;
            
            // Create plugin's own trash folder
            $trash_dir = $upload_dir['basedir'] . '/packshotphoto-trash';
            if (!file_exists($trash_dir)) {
                \wp_mkdir_p($trash_dir);
            }
            
            $backup_path = $trash_dir . '/' . $backup_name;
            $backup_rel  = 'packshotphoto-trash/' . $backup_name;
            
            // Handle backup - ALWAYS save meta if trash mode
            if (file_exists($file_path)) {
                // Original file still exists - move to trash
                if (!file_exists($backup_path)) {
                    global $wp_filesystem;
                    if (empty($wp_filesystem)) {
                        require_once ABSPATH . 'wp-admin/includes/file.php';
                        WP_Filesystem();
                    }
                    if (!empty($wp_filesystem)) {
                        $wp_filesystem->move($file_path, $backup_path, true);
                    }
                }
                \update_post_meta($post_id, '_pmm_original_backup', $backup_rel);
                // Cache flag for fast column rendering (avoid 8 FS ops per row!)
                \update_post_meta($post_id, '_pmm_has_file_backup', '1');
            } else {
                // Original file doesn't exist (shouldn't happen normally)
                // But we still set meta if backup file exists
                if (file_exists($backup_path)) {
                    \update_post_meta($post_id, '_pmm_original_backup', $backup_rel);
                    \update_post_meta($post_id, '_pmm_has_file_backup', '1');
                }
            }
        }

        $before_size = $original_filesize;
        $after_size = filesize($webp_path);

        return [
            'success' => true,
            'message' => __('Converted to WEBP!', 'packshotphoto-ai'),
            'data'    => [
                'url'            => $upload_dir['baseurl'] . '/' . $relative_path,
                'path'           => $webp_path,
                'new_filename'   => basename($webp_path),
                'new_url'        => $upload_dir['baseurl'] . '/' . $relative_path . '?t=' . time(),
                'before_format'  => strtoupper($original_extension),
                'after_format'   => 'WEBP',
                'before_size'    => size_format($before_size),
                'after_size'     => size_format($after_size),
                'savings'        => $before_size > 0 ? round((($before_size - $after_size) / $before_size) * 100, 1) : 0,
            ],
        ];
    }

    /**
     * Generate attachment metadata with WEBP thumbnails
     * Uses our own conversion logic instead of WordPress image editor
     *
     * @param int    $post_id    Attachment ID
     * @param string $webp_path  Path to the main WEBP file
     * @return array Attachment metadata
     */
    private function generate_webp_metadata(int $post_id, string $webp_path): array {
        Logger::info('WEBP: Starting metadata generation', ['post_id' => $post_id, 'path' => $webp_path]);
        
        // Get image dimensions from WEBP file
        $image_data = @getimagesize($webp_path);
        if (!$image_data) {
            Logger::error('WEBP: Cannot get image dimensions for metadata', ['path' => $webp_path]);
            return [];
        }
        
        [$width, $height] = $image_data;
        $filename = basename($webp_path);
        // WordPress needs relative path from uploads dir (e.g. '2026/04/file.webp'), not just basename
        $relative_file = \_wp_relative_upload_path($webp_path);
        
        // Build metadata array with required fields
        $metadata = [
            'width'    => $width,
            'height'   => $height,
            'file'     => $relative_file,
            'filesize' => filesize($webp_path),
            'sizes'    => [],
        ];
        
        // Guard: skip if image has zero dimensions
        if ($width <= 0 || $height <= 0) {
            Logger::warning('WEBP: Skipping metadata generation — zero dimensions', ['width' => $width, 'height' => $height]);
            return [];
        }
        
        // Get registered thumbnail sizes from WordPress
        $registered_sizes = \wp_get_registered_image_subsizes();
        Logger::info('WEBP: Registered sizes count', ['count' => count($registered_sizes), 'sizes' => array_keys($registered_sizes), 'image_size' => $width . 'x' . $height]);
        
        // Generate WEBP thumbnail for each size
        $generated_count = 0;
        foreach ($registered_sizes as $size_name => $size_info) {
            // Calculate thumbnail dimensions maintaining aspect ratio
            $thumb_width = $size_info['width'];
            $thumb_height = $size_info['height'];
            $thumb_crop = $size_info['crop'] ?? false;
            
            // Skip sizes with invalid dimensions (zero or negative)
            if ($thumb_width <= 0 || $thumb_height <= 0) {
                Logger::debug('WEBP: Skipping size - invalid dimensions', [
                    'size' => $size_name,
                    'w' => $thumb_width,
                    'h' => $thumb_height
                ]);
                continue;
            }
            
            // For full size - always create it
            if ($size_name === 'full') {
                Logger::debug('WEBP: Processing full size', ['size' => $size_name]);
            } else {
                Logger::debug('WEBP: Size will be generated', [
                    'size' => $size_name,
                    'thumb' => $thumb_width . 'x' . $thumb_height,
                    'original' => $width . 'x' . $height,
                    'would_upscale' => ($thumb_width > $width || $thumb_height > $height)
                ]);
            }
            
            // Calculate crop/resize dimensions
            if (!empty($size_info['crop'])) {
                // Crop mode - use exact dimensions
                $new_width = $thumb_width;
                $new_height = $thumb_height;
                Logger::debug('WEBP: Using crop mode', ['size' => $size_name, 'crop' => $thumb_width . 'x' . $thumb_height]);
            } else {
                // Resize mode - maintain aspect ratio
                $ratio = min($width / $thumb_width, $height / $thumb_height);
                $new_width = (int) round($width / $ratio);
                $new_height = (int) round($height / $ratio);
                Logger::debug('WEBP: Using resize mode', ['size' => $size_name, 'original' => $width . 'x' . $height, 'target' => $new_width . 'x' . $new_height]);
            }
            
            // Generate thumbnail filename
            $path_info = pathinfo($webp_path);
            $thumb_filename = $path_info['filename'] . '-' . $new_width . 'x' . $new_height . '.webp';
            $thumb_path = $path_info['dirname'] . '/' . $thumb_filename;
            
            // Create thumbnail using our conversion method
            if ($this->create_webp_thumbnail($webp_path, $thumb_path, $new_width, $new_height)) {
                $metadata['sizes'][$size_name] = [
                    'file'      => $thumb_filename,
                    'width'     => $new_width,
                    'height'    => $new_height,
                    'filesize'  => filesize($thumb_path),
                    'mime-type' => 'image/webp',
                ];
                $generated_count++;
            }
        }
        
        Logger::info('WEBP: Generated thumbnails', ['count' => $generated_count, 'sizes' => array_keys($metadata['sizes'])]);
        
        return $metadata;
    }

    /**
     * Create a WEBP thumbnail at specific dimensions
     *
     * @param string $source_path Source WEBP file
     * @param string $dest_path   Destination thumbnail path
     * @param int    $width       Target width
     * @param int    $height       Target height
     * @return bool Success
     */
    private function create_webp_thumbnail(string $source_path, string $dest_path, int $width, int $height): bool {
        Logger::info('WEBP: Creating thumbnail', ['source' => $source_path, 'dest' => $dest_path, 'size' => $width . 'x' . $height]);
        
        // Try Imagick first (better quality and resizing)
        if (extension_loaded('imagick')) {
            try {
                $imagick = new \Imagick($source_path);
                $imagick->setImageFormat('webp');
                $imagick->setImageCompressionQuality(self::DEFAULT_QUALITY);
                
                // Use resizeImage instead of thumbnailImage to allow upscaling
                // thumbnailImage doesn't upscale by default
                $imagick->resizeImage($width, $height, \Imagick::FILTER_LANCZOS, 1);
                
                $imagick->writeImage($dest_path);
                $imagick->destroy();
                
                $success = file_exists($dest_path) && filesize($dest_path) > 0;
                Logger::info('WEBP: Thumbnail created (Imagick)', ['dest' => $dest_path, 'success' => $success]);
                return $success;
            } catch (\Exception $e) {
                Logger::error('WEBP: Imagick failed', ['error' => $e->getMessage()]);
                // Fall through to GD
            }
        }
        
        // Fallback to GD - need to resize then convert
        if (!function_exists('imagewebp')) {
            Logger::error('WEBP: No GD function imagewebp');
            return false;
        }
        
        // Load source image (we already know it's WEBP from source)
        $source = @imagecreatefromwebp($source_path);
        if (!$source) {
            return false;
        }
        
        // Create resized image
        $thumb = imagecreatetruecolor($width, $height);
        if (!$thumb) {
            imagedestroy($source);
            return false;
        }
        
        // Preserve transparency for WEBP
        imagealphablending($thumb, false);
        imagesavealpha($thumb, true);
        
        // Resize with resampling
        imagecopyresampled($thumb, $source, 0, 0, 0, 0, $width, $height, imagesx($source), imagesy($source));
        
        // Save as WEBP
        $result = imagewebp($thumb, $dest_path, self::DEFAULT_QUALITY);
        
        imagedestroy($source);
        imagedestroy($thumb);
        
        return $result && file_exists($dest_path) && filesize($dest_path) > 0;
    }

    /**
     * Perform the actual conversion
     *
     * @param string $source_path Source file path
     * @param string $dest_path   Destination WEBP path
     * @return bool Success
     */
    private function do_conversion(string $source_path, string $dest_path): bool {
        Logger::info('WebPConverter: do_conversion() started', [
            'source' => $source_path,
            'dest' => $dest_path,
            'source_exists' => file_exists($source_path)
        ]);
        
        MemoryManager::ensure_memory_limit();
        $mime = @mime_content_type($source_path);
        
        Logger::info('WebPConverter: mime type detected', ['mime' => $mime]);

        if (extension_loaded('imagick')) {
            try {
                $imagick = new \Imagick($source_path);
                $imagick->setImageFormat('webp');
                $imagick->setImageCompressionQuality(self::DEFAULT_QUALITY);
                $imagick->stripImage();
                $imagick->writeImage($dest_path);
                $imagick->clear();
                $imagick->destroy();
                $success = file_exists($dest_path) && filesize($dest_path) > 0;
                Logger::info('WebPConverter: Imagick conversion result', ['success' => $success, 'dest' => $dest_path]);
                return $success;
            } catch (\Exception $e) {
                Logger::debug('WEBP: Imagick conversion failed, falling back to GD', ['error' => $e->getMessage()]);
            }
        }

        if (!function_exists('imagewebp')) {
            Logger::warning('WebPConverter: GD imagewebp function not available');
            return false;
        }

        Logger::info('WebPConverter: Using GD fallback', ['mime' => $mime]);

        switch ($mime) {
            case 'image/jpeg':
                $image = imagecreatefromjpeg($source_path);
                break;
            case 'image/png':
                $image = @imagecreatefrompng($source_path);
                if ($image) {
                    imagepalettetotruecolor($image);
                    imagealphablending($image, true);
                    imagesavealpha($image, true);
                }
                break;
            case 'image/gif':
                $image = @imagecreatefromgif($source_path);
                break;
            case 'image/webp':
                $image = @imagecreatefromwebp($source_path);
                break;
            case 'image/avif':
                $image = @imagecreatefromavif($source_path);
                break;
            default:
                Logger::warning('WebPConverter: Unsupported mime type', ['mime' => $mime]);
                return false;
        }

        if (!$image) {
            Logger::error('WebPConverter: Failed to create image resource from source');
            return false;
        }

        $result = imagewebp($image, $dest_path, self::DEFAULT_QUALITY);
        imagedestroy($image);

        $success = $result && file_exists($dest_path) && filesize($dest_path) > 0;
        Logger::info('WebPConverter: GD conversion result', ['success' => $success, 'dest' => $dest_path]);
        
        return $success;
    }
}
