<?php

/**
 * JCOGS Image Pro - Compression Provider Interface
 * Extension Architecture Foundation
 * 
 * @category   ExpressionEngine Add-on
 * @package    JCOGS Image Pro
 * @author     JCOGS Design <contact@jcogs.net>
 * @copyright  Copyright (c) 2021 - 2025 JCOGS Design
 * @license    https://jcogs.net/add-ons/license/jcogs_img_pro
 * @version    2.0.6
 * @link       https://JCOGS.net/
 * @since      Extension Architecture v2.0
 */

namespace JCOGSDesign\JCOGSImagePro\Service\Provider;

/**
 * Compression Provider Interface
 * 
 * STUB INTERFACE - Full implementation planned for v2.1.0
 * 
 * Post-processing compression for generated cache files. Providers implement
 * advanced compression algorithms (lossy/lossless) to reduce file sizes beyond
 * GD/Imagick's built-in compression.
 * 
 * Use Cases (v2.1.0+):
 * - mozjpeg compression (better JPEG compression than standard libjpeg)
 * - pngquant optimization (lossy PNG compression with quality preservation)
 * - TinyPNG/TinyJPG API (cloud-based optimization)
 * - WebP advanced encoding options
 * - AVIF encoding for next-gen format
 * - Lossless optimization (OptiPNG, JpegTran, etc.)
 * 
 * Priority Levels:
 * - 10: Core GD/Imagick compression (baseline)
 * - 20-30: Local optimization tools (mozjpeg, pngquant)
 * - 40-50: Advanced local algorithms
 * - 100+: Cloud API compression (TinyPNG, Kraken.io, etc.)
 * 
 * Integration Point (v2.1.0):
 * SaveImageStage will call CompressionProvider AFTER writing cache file.
 * Provider reads file, applies compression, writes optimized version back.
 * Original file replaced with compressed version if smaller.
 * 
 * Compression Strategy (v2.1.0):
 * - Check if provider available for image format
 * - Compare savings vs. cost (API providers may charge)
 * - Log compression stats (original size, compressed size, savings)
 * - Fall back to core compression if provider fails
 * 
 * Extension add-ons can implement this interface and register their
 * providers via the 'jcogs_img_pro_register_providers' extension hook.
 * 
 * Note: This is a STUB INTERFACE for v2.0.0. Method signatures are defined
 * but not yet integrated into SaveImageStage. Full implementation including
 * pipeline integration is deferred to v2.1.0.
 * 
 * Example Implementation (v2.1.0):
 * 
 * ```php
 * class MozjpegCompressionProvider implements CompressionProviderInterface
 * {
 *     public function getName(): string { return 'mozjpeg'; }
 *     public function getSupportedFormats(): array { return ['image/jpeg']; }
 *     public function getPriority(): int { return 25; }
 *     
 *     public function isAvailable(): bool
 *     {
 *         // Check if mozjpeg binary available
 *         return $this->_findBinary('cjpeg') !== null;
 *     }
 *     
 *     public function compress(string $filePath, array $options): array
 *     {
 *         $original_size = filesize($filePath);
 *         
 *         // Build mozjpeg command
 *         $temp_file = tempnam(sys_get_temp_dir(), 'mozjpeg_');
 *         $quality = $options['quality'] ?? 90;
 *         
 *         $cmd = sprintf(
 *             'cjpeg -quality %d -optimize -progressive %s > %s',
 *             $quality,
 *             escapeshellarg($filePath),
 *             escapeshellarg($temp_file)
 *         );
 *         
 *         exec($cmd, $output, $return_code);
 *         
 *         if ($return_code === 0 && file_exists($temp_file)) {
 *             $compressed_size = filesize($temp_file);
 *             
 *             // Only use compressed version if smaller
 *             if ($compressed_size < $original_size) {
 *                 rename($temp_file, $filePath);
 *                 
 *                 return [
 *                     'success' => true,
 *                     'original_size' => $original_size,
 *                     'compressed_size' => $compressed_size,
 *                     'savings_percent' => round((1 - $compressed_size / $original_size) * 100, 2),
 *                     'method' => 'mozjpeg',
 *                     'error' => null,
 *                 ];
 *             }
 *         }
 *         
 *         return ['success' => false, 'error' => 'Compression not beneficial'];
 *     }
 *     
 *     public function getCostPerCompression(): ?float { return null; }
 * }
 * ```
 * 
 * Template Usage (v2.1.0):
 * Compression is automatic - no template changes needed. Provider selection
 * based on format and priority. Results logged for debugging.
 */
interface CompressionProviderInterface
{
    /**
     * Get provider name for logging/debugging
     * 
     * @return string Provider identifier (e.g., 'mozjpeg', 'tinypng_api', 'pngquant')
     */
    public function getName(): string;
    
    /**
     * Get supported image formats
     * 
     * Returns array of MIME types this provider can compress.
     * Provider only called for matching formats.
     * 
     * @return array Supported MIME types (e.g., ['image/jpeg'], ['image/png'], ['image/jpeg', 'image/png'])
     */
    public function getSupportedFormats(): array;
    
    /**
     * Get provider priority (higher = preferred if multiple providers support format)
     * 
     * Priority Guidelines:
     * - 10: Core GD/Imagick compression
     * - 20-30: Local tools (mozjpeg, pngquant)
     * - 40-50: Advanced local algorithms
     * - 100+: Cloud API compression
     * 
     * @return int Priority value
     */
    public function getPriority(): int;
    
    /**
     * Check if provider is available
     * 
     * Should verify:
     * - Required binaries present (cjpeg, pngquant, etc.)
     * - API credentials configured (if applicable)
     * - System requirements met
     * 
     * Return false if compression cannot function. Do not throw exceptions.
     * 
     * @return bool True if compression can be used
     */
    public function isAvailable(): bool;
    
    /**
     * Compress image file
     * 
     * Called AFTER image written to cache by SaveImageStage. Provider reads
     * file, applies compression, and writes optimized version back.
     * 
     * Optimization Strategy:
     * - Only replace original if compressed version is smaller
     * - Preserve image quality within acceptable limits
     * - Respect user's quality setting from options
     * - Log compression results for debugging
     * 
     * Performance Considerations:
     * - Keep execution time reasonable (< 500ms for local, < 3s for API)
     * - Use temp files to avoid corrupting original on failure
     * - Clean up temp files in all code paths
     * 
     * Error Handling:
     * - Return success=false on error (graceful degradation)
     * - Include error message in result for logging
     * - Original file must remain intact on error
     * 
     * @param string $filePath Absolute path to cache file
     * @param array $options Compression options from context:
     *   [
     *     'quality' => int,                  // Quality setting (0-100)
     *     'format' => string,                // MIME type (e.g., 'image/jpeg')
     *     'original_size' => int,            // Original file size (bytes)
     *     'lossy' => bool,                   // Allow lossy compression
     *     'preserve_metadata' => bool,       // Keep EXIF/IPTC data
     *   ]
     * 
     * @return array Compression result:
     *   [
     *     'success' => bool,                 // True if compression succeeded
     *     'original_size' => int,            // Bytes before compression
     *     'compressed_size' => int,          // Bytes after compression
     *     'savings_percent' => float,        // Percentage saved (0-100)
     *     'method' => string,                // Compression method used
     *     'error' => string|null,            // Error message if failed, null if success
     *   ]
     */
    public function compress(string $filePath, array $options): array;
    
    /**
     * Get estimated cost per compression (if applicable)
     * 
     * For API-based compression providers, return cost in USD.
     * For local/free providers, return null.
     * 
     * Used for cost tracking and provider selection logic.
     * 
     * @return float|null Cost in USD, or null if free/included
     */
    public function getCostPerCompression(): ?float;
}
