<?php

namespace App\Services;

use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class ImageService
{
    protected ImageManager $manager;

    public function __construct()
    {
        $this->manager = new ImageManager(new Driver());
    }

    /**
     * Resize and compress image for banners
     * 
     * @param UploadedFile $file
     * @param int $maxWidth Maximum width (default: 1920)
     * @param int $maxHeight Maximum height (default: 600)
     * @param int $quality JPEG quality 1-100 (default: 85)
     * @return string Storage path
     */
    public function processBannerImage(UploadedFile $file, int $maxWidth = 1920, int $maxHeight = 600, int $quality = 85): string
    {
        $image = $this->manager->read($file->getRealPath());
        
        // Get original dimensions
        $width = $image->width();
        $height = $image->height();
        
        // Resize if larger than max dimensions (maintains aspect ratio)
        if ($width > $maxWidth || $height > $maxHeight) {
            $image->scaleDown($maxWidth, $maxHeight);
        }
        
        // Generate unique filename - always save as JPEG for better compression
        $filename = 'banners/' . Str::random(40) . '.jpg';
        $path = storage_path('app/public/' . $filename);
        
        // Ensure directory exists
        $directory = dirname($path);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }
        
        // Convert to RGB and save as JPEG with compression
        $image->toJpeg($quality)->save($path);
        
        return $filename;
    }

    /**
     * Resize and compress image for products
     * 
     * @param UploadedFile $file
     * @param int $maxWidth Maximum width (default: 800)
     * @param int $maxHeight Maximum height (default: 800)
     * @param int $quality JPEG quality 1-100 (default: 85)
     * @return string Storage path
     */
    public function processProductImage(UploadedFile $file, int $maxWidth = 800, int $maxHeight = 800, int $quality = 85): string
    {
        $image = $this->manager->read($file->getRealPath());
        
        // Resize if larger than max dimensions
        if ($image->width() > $maxWidth || $image->height() > $maxHeight) {
            $image->scaleDown($maxWidth, $maxHeight);
        }
        
        // Generate unique filename - save as JPEG for compression
        $filename = 'products/' . Str::random(40) . '.jpg';
        $path = storage_path('app/public/' . $filename);
        
        // Ensure directory exists
        $directory = dirname($path);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }
        
        // Save as JPEG with compression
        $image->toJpeg($quality)->save($path);
        
        return $filename;
    }

    /**
     * Resize and compress image for categories
     * 
     * @param UploadedFile $file
     * @param int $maxWidth Maximum width (default: 400)
     * @param int $maxHeight Maximum height (default: 400)
     * @param int $quality JPEG quality 1-100 (default: 85)
     * @return string Storage path
     */
    public function processCategoryImage(UploadedFile $file, int $maxWidth = 400, int $maxHeight = 400, int $quality = 85): string
    {
        $image = $this->manager->read($file->getRealPath());
        
        // Resize if larger than max dimensions
        if ($image->width() > $maxWidth || $image->height() > $maxHeight) {
            $image->scaleDown($maxWidth, $maxHeight);
        }
        
        // Generate unique filename - save as JPEG for compression
        $filename = 'categories/' . Str::random(40) . '.jpg';
        $path = storage_path('app/public/' . $filename);
        
        // Ensure directory exists
        $directory = dirname($path);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }
        
        // Save as JPEG with compression
        $image->toJpeg($quality)->save($path);
        
        return $filename;
    }

    /**
     * Resize and compress image for user profiles
     * 
     * @param UploadedFile $file
     * @param int $maxWidth Maximum width (default: 400)
     * @param int $maxHeight Maximum height (default: 400)
     * @param int $quality JPEG quality 1-100 (default: 85)
     * @return string Storage path
     */
    public function processProfileImage(UploadedFile $file, int $maxWidth = 400, int $maxHeight = 400, int $quality = 85): string
    {
        $image = $this->manager->read($file->getRealPath());
        
        // Resize if larger than max dimensions
        if ($image->width() > $maxWidth || $image->height() > $maxHeight) {
            $image->scaleDown($maxWidth, $maxHeight);
        }
        
        // Generate unique filename - save as JPEG for compression
        $filename = 'profiles/' . Str::random(40) . '.jpg';
        $path = storage_path('app/public/' . $filename);
        
        // Ensure directory exists
        $directory = dirname($path);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }
        
        // Save as JPEG with compression
        $image->toJpeg($quality)->save($path);
        
        return $filename;
    }

    /**
     * Get image file size in KB
     */
    public function getFileSize(string $path): float
    {
        $fullPath = storage_path('app/public/' . $path);
        if (file_exists($fullPath)) {
            return round(filesize($fullPath) / 1024, 2);
        }
        return 0;
    }

    /**
     * Process product image into original + four size variants (thumb, small, medium, large).
     * Creates directory storage/app/public/products/{product_id}/. Prefers WebP; falls back to JPEG if WebP fails.
     *
     * @param UploadedFile $file
     * @param int $productId
     * @return array Relative storage paths keyed by original, thumb, small, medium, large
     */
    public function processProductImageVariants(UploadedFile $file, int $productId): array
    {
        // GD/Intervention load full image into memory; variants + clones can exceed 128MB
        @ini_set('memory_limit', '512M');

        $baseDir = "products/{$productId}";
        $fullDir = storage_path('app/public/' . $baseDir);
        if (!is_dir($fullDir)) {
            mkdir($fullDir, 0755, true);
        }

        $ext = strtolower($file->getClientOriginalExtension() ?: 'jpg');
        if (!in_array($ext, ['jpg', 'jpeg', 'png', 'webp'], true)) {
            $ext = 'jpg';
        }
        $originalFilename = 'original.' . $ext;
        $originalPath = $baseDir . '/' . $originalFilename;

        try {
            $image = $this->manager->read($file->getRealPath());
            $image->save($fullDir . '/' . $originalFilename);

            $fileSizeKb = $file->getSize() / 1024;
            // Skip-compression branch: if uploaded file size < 100 KB, use higher quality (only resize)
            $qualityWebp = $fileSizeKb < 100 ? 85 : 67;
            $qualityJpeg = $fileSizeKb < 100 ? 85 : 72;

            $variants = [
                'thumb' => 150,
                'small' => 300,
                'medium' => 600,
                'large' => 1200,
            ];
            $result = ['original' => $originalPath];

            foreach ($variants as $sizeKey => $maxWidth) {
                $img = $this->manager->read($file->getRealPath());
                if ($img->width() > $maxWidth) {
                    $img->scaleDown($maxWidth);
                }
                $variantPath = $fullDir . '/' . $sizeKey;
                try {
                    $img->toWebp($qualityWebp)->save($variantPath . '.webp');
                    $result[$sizeKey] = $baseDir . '/' . $sizeKey . '.webp';
                } catch (\Throwable $e) {
                    // WebP vs JPEG fallback: WebP not supported (e.g. GD not compiled with WebP); use JPEG
                    $img->toJpeg($qualityJpeg)->save($variantPath . '.jpg');
                    $result[$sizeKey] = $baseDir . '/' . $sizeKey . '.jpg';
                }
            }

            $result['version'] = (string) time();

            return $result;
        } catch (\Throwable $e) {
            // Save original only on error; do not rethrow so create/update can still succeed
            try {
                $fallback = $this->manager->read($file->getRealPath());
                $fallback->save($fullDir . '/' . $originalFilename);
            } catch (\Throwable $inner) {
                // ignore
            }
            return ['original' => $originalPath, 'version' => (string) time()];
        }
    }

    /**
     * Delete product image folder and all files inside it (and legacy single file if path outside folder).
     *
     * @param int $productId
     * @param string|null $legacyImagePath Relative path (e.g. products/xyz.jpg) to delete if not under products/{id}/
     */
    public function deleteProductImageFolder(int $productId, ?string $legacyImagePath = null): void
    {
        $dir = "products/{$productId}";
        $fullDir = storage_path('app/public/' . $dir);
        if (is_dir($fullDir)) {
            $files = glob($fullDir . '/*');
            foreach ($files as $f) {
                if (is_file($f)) {
                    @unlink($f);
                }
            }
            @rmdir($fullDir);
        }
        if ($legacyImagePath !== null && $legacyImagePath !== '' && strpos($legacyImagePath, $dir . '/') !== 0) {
            Storage::disk('public')->delete($legacyImagePath);
        }
    }
}

