<?php

namespace App\Services;

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

/**
 * Service centralisé pour la gestion des images
 * Utilisé pour tous les types: produits, investissements, profils, KYC
 */
class ImageService
{
    // Configuration par défaut
    protected array $config = [
        'max_width' => 1200,
        'max_height' => 1200,
        'thumbnail_width' => 300,
        'thumbnail_height' => 300,
        'quality' => 80,
        'allowed_mimes' => ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
        'max_size' => 5 * 1024 * 1024, // 5 Mo
    ];

    /**
     * Stocker une image avec redimensionnement et copie Windows
     */
    public function store(
        UploadedFile $file,
        string $folder,
        ?string $customName = null,
        bool $createThumbnail = true,
        bool $resize = true
    ): array {
        // Générer le nom de fichier
        $extension = $file->getClientOriginalExtension() ?: 'jpg';
        $filename = $customName 
            ? $customName . '.' . $extension
            : time() . '_' . $this->sanitizeFilename($file->getClientOriginalName());

        // Chemin relatif
        $relativePath = $folder . '/' . $filename;

        // Traiter l'image (redimensionnement + compression)
        if ($resize && $this->canProcessImage()) {
            $processedImage = $this->processImage($file, $this->config['max_width'], $this->config['max_height'], $this->config['quality']);
        } else {
            $processedImage = file_get_contents($file->getRealPath());
        }

        // Stocker dans storage/app/public
        Storage::disk('public')->put($relativePath, $processedImage);

        // Copier vers public/storage (Windows/cPanel compatibilité)
        $this->copyToPublic($relativePath, $processedImage);

        $result = [
            'path' => $relativePath,
            'filename' => $filename,
            'url' => asset('storage/' . $relativePath),
            'size' => strlen($processedImage),
            'original_size' => $file->getSize(),
        ];

        // Créer la miniature
        if ($createThumbnail && $this->canProcessImage()) {
            $thumbnailPath = $this->createThumbnail($file, $folder, $filename);
            if ($thumbnailPath) {
                $result['thumbnail_path'] = $thumbnailPath;
                $result['thumbnail_url'] = asset('storage/' . $thumbnailPath);
            }
        }

        return $result;
    }

    /**
     * Stocker plusieurs images
     */
    public function storeMultiple(array $files, string $folder, bool $createThumbnails = true): array
    {
        $results = [];
        foreach ($files as $index => $file) {
            if ($file instanceof UploadedFile && $file->isValid()) {
                try {
                    $results[] = $this->store($file, $folder, null, $createThumbnails);
                } catch (\Exception $e) {
                    Log::error("Erreur upload image {$index}: " . $e->getMessage());
                }
            }
        }
        return $results;
    }

    /**
     * Traiter l'image: redimensionner et compresser
     */
    protected function processImage(UploadedFile $file, int $maxWidth, int $maxHeight, int $quality): string
    {
        $sourceImage = $this->createImageFromFile($file);
        if (!$sourceImage) {
            return file_get_contents($file->getRealPath());
        }

        $originalWidth = imagesx($sourceImage);
        $originalHeight = imagesy($sourceImage);

        // Calculer les nouvelles dimensions en gardant le ratio
        $ratio = min($maxWidth / $originalWidth, $maxHeight / $originalHeight);
        
        // Ne pas agrandir les petites images
        if ($ratio >= 1) {
            $newWidth = $originalWidth;
            $newHeight = $originalHeight;
        } else {
            $newWidth = (int) round($originalWidth * $ratio);
            $newHeight = (int) round($originalHeight * $ratio);
        }

        // Créer la nouvelle image
        $newImage = imagecreatetruecolor($newWidth, $newHeight);

        // Préserver la transparence pour PNG et GIF
        $mimeType = $file->getMimeType();
        if (in_array($mimeType, ['image/png', 'image/gif'])) {
            imagealphablending($newImage, false);
            imagesavealpha($newImage, true);
            $transparent = imagecolorallocatealpha($newImage, 255, 255, 255, 127);
            imagefilledrectangle($newImage, 0, 0, $newWidth, $newHeight, $transparent);
        } else {
            // Fond blanc pour JPEG
            $white = imagecolorallocate($newImage, 255, 255, 255);
            imagefilledrectangle($newImage, 0, 0, $newWidth, $newHeight, $white);
        }

        // Redimensionner
        imagecopyresampled($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight);

        // Récupérer l'image en string
        ob_start();
        switch ($mimeType) {
            case 'image/png':
                imagepng($newImage, null, min(9, (int) round((100 - $quality) / 10)));
                break;
            case 'image/gif':
                imagegif($newImage);
                break;
            case 'image/webp':
                if (function_exists('imagewebp')) {
                    imagewebp($newImage, null, $quality);
                } else {
                    imagejpeg($newImage, null, $quality);
                }
                break;
            default:
                imagejpeg($newImage, null, $quality);
        }
        $imageData = ob_get_clean();

        // Libérer la mémoire
        imagedestroy($sourceImage);
        imagedestroy($newImage);

        return $imageData;
    }

    /**
     * Créer une miniature
     */
    protected function createThumbnail(UploadedFile $file, string $folder, string $filename): ?string
    {
        $sourceImage = $this->createImageFromFile($file);
        if (!$sourceImage) {
            return null;
        }

        $originalWidth = imagesx($sourceImage);
        $originalHeight = imagesy($sourceImage);

        // Calculer les dimensions de la miniature (crop carré au centre)
        $thumbWidth = $this->config['thumbnail_width'];
        $thumbHeight = $this->config['thumbnail_height'];

        // Crop carré au centre
        $size = min($originalWidth, $originalHeight);
        $srcX = (int) (($originalWidth - $size) / 2);
        $srcY = (int) (($originalHeight - $size) / 2);

        $thumbnail = imagecreatetruecolor($thumbWidth, $thumbHeight);

        // Préserver transparence
        imagealphablending($thumbnail, false);
        imagesavealpha($thumbnail, true);

        imagecopyresampled($thumbnail, $sourceImage, 0, 0, $srcX, $srcY, $thumbWidth, $thumbHeight, $size, $size);

        // Nom du thumbnail
        $pathInfo = pathinfo($filename);
        $thumbFilename = $pathInfo['filename'] . '_thumb.' . ($pathInfo['extension'] ?? 'jpg');
        $thumbPath = $folder . '/thumbnails/' . $thumbFilename;

        // Sauvegarder
        ob_start();
        imagejpeg($thumbnail, null, $this->config['quality']);
        $thumbData = ob_get_clean();

        Storage::disk('public')->put($thumbPath, $thumbData);
        $this->copyToPublic($thumbPath, $thumbData);

        imagedestroy($sourceImage);
        imagedestroy($thumbnail);

        return $thumbPath;
    }

    /**
     * Créer une ressource image depuis le fichier
     */
    protected function createImageFromFile(UploadedFile $file): ?\GdImage
    {
        $mimeType = $file->getMimeType();
        $path = $file->getRealPath();

        try {
            switch ($mimeType) {
                case 'image/jpeg':
                    return imagecreatefromjpeg($path);
                case 'image/png':
                    return imagecreatefrompng($path);
                case 'image/gif':
                    return imagecreatefromgif($path);
                case 'image/webp':
                    if (function_exists('imagecreatefromwebp')) {
                        return imagecreatefromwebp($path);
                    }
                    return null;
                default:
                    return null;
            }
        } catch (\Exception $e) {
            Log::warning("Impossible de créer l'image depuis {$path}: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Copier vers public/storage pour Windows/cPanel
     */
    protected function copyToPublic(string $relativePath, string $content): void
    {
        $publicPath = public_path('storage/' . $relativePath);
        $directory = dirname($publicPath);

        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }

        file_put_contents($publicPath, $content);
    }

    /**
     * Supprimer une image et sa miniature
     */
    public function delete(string $path): bool
    {
        $deleted = false;

        // Supprimer du storage
        if (Storage::disk('public')->exists($path)) {
            Storage::disk('public')->delete($path);
            $deleted = true;
        }

        // Supprimer de public/storage
        $publicPath = public_path('storage/' . $path);
        if (file_exists($publicPath)) {
            unlink($publicPath);
            $deleted = true;
        }

        // Supprimer la miniature
        $pathInfo = pathinfo($path);
        $folder = $pathInfo['dirname'];
        $thumbPath = $folder . '/thumbnails/' . $pathInfo['filename'] . '_thumb.' . ($pathInfo['extension'] ?? 'jpg');

        if (Storage::disk('public')->exists($thumbPath)) {
            Storage::disk('public')->delete($thumbPath);
        }
        $publicThumbPath = public_path('storage/' . $thumbPath);
        if (file_exists($publicThumbPath)) {
            unlink($publicThumbPath);
        }

        return $deleted;
    }

    /**
     * Vérifier si GD est disponible
     */
    public function canProcessImage(): bool
    {
        return extension_loaded('gd') && function_exists('imagecreatetruecolor');
    }

    /**
     * Nettoyer le nom de fichier
     */
    protected function sanitizeFilename(string $filename): string
    {
        return preg_replace('/[^a-zA-Z0-9._-]/', '_', $filename);
    }

    /**
     * Valider un fichier image
     */
    public function validate(UploadedFile $file): array
    {
        $errors = [];

        if (!$file->isValid()) {
            $errors[] = 'Fichier invalide';
            return $errors;
        }

        if ($file->getSize() > $this->config['max_size']) {
            $maxMb = $this->config['max_size'] / 1024 / 1024;
            $errors[] = "Le fichier dépasse la taille maximale de {$maxMb} Mo";
        }

        if (!in_array($file->getMimeType(), $this->config['allowed_mimes'])) {
            $errors[] = 'Format non supporté. Formats acceptés: JPEG, PNG, GIF, WEBP';
        }

        return $errors;
    }

    /**
     * Valider plusieurs fichiers
     */
    public function validateMultiple(array $files, int $maxFiles = 10): array
    {
        $errors = [];

        if (count($files) > $maxFiles) {
            $errors[] = "Maximum {$maxFiles} images autorisées";
        }

        foreach ($files as $index => $file) {
            $fileErrors = $this->validate($file);
            foreach ($fileErrors as $error) {
                $errors[] = "Image " . ($index + 1) . ": " . $error;
            }
        }

        return $errors;
    }

    /**
     * Configurer le service
     */
    public function configure(array $config): self
    {
        $this->config = array_merge($this->config, $config);
        return $this;
    }

    /**
     * Obtenir l'URL d'une image avec fallback
     */
    public static function getUrl(?string $path, string $default = '/images/no-image.svg'): string
    {
        if (!$path) {
            return asset($default);
        }

        if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://')) {
            return $path;
        }

        if (str_contains($path, 'storage/')) {
            return asset($path);
        }

        return asset('storage/' . $path);
    }

    /**
     * Obtenir l'URL de la miniature
     */
    public static function getThumbnailUrl(?string $path, string $default = '/images/no-image.svg'): string
    {
        if (!$path) {
            return asset($default);
        }

        $pathInfo = pathinfo($path);
        $folder = $pathInfo['dirname'];
        $thumbPath = $folder . '/thumbnails/' . $pathInfo['filename'] . '_thumb.' . ($pathInfo['extension'] ?? 'jpg');

        // Vérifier si le thumbnail existe
        if (Storage::disk('public')->exists($thumbPath)) {
            return asset('storage/' . $thumbPath);
        }

        // Sinon retourner l'image originale
        return self::getUrl($path, $default);
    }

    /**
     * Migrer une image existante (redimensionner + créer miniature)
     */
    public function migrateExisting(string $path, string $folder): ?array
    {
        $fullPath = storage_path('app/public/' . $path);
        
        if (!file_exists($fullPath)) {
            // Essayer dans public/storage
            $fullPath = public_path('storage/' . $path);
            if (!file_exists($fullPath)) {
                return null;
            }
        }

        try {
            $mimeType = mime_content_type($fullPath);
            $content = file_get_contents($fullPath);
            
            // Créer un fichier temporaire pour utiliser les méthodes existantes
            $tempPath = sys_get_temp_dir() . '/' . basename($path);
            file_put_contents($tempPath, $content);

            // Redimensionner si possible
            if ($this->canProcessImage()) {
                $image = $this->createImageFromPath($fullPath, $mimeType);
                if ($image) {
                    $width = imagesx($image);
                    $height = imagesy($image);
                    
                    // Redimensionner si nécessaire
                    $ratio = min($this->config['max_width'] / $width, $this->config['max_height'] / $height);
                    if ($ratio < 1) {
                        $newWidth = (int) round($width * $ratio);
                        $newHeight = (int) round($height * $ratio);
                        
                        $newImage = imagecreatetruecolor($newWidth, $newHeight);
                        imagecopyresampled($newImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
                        
                        ob_start();
                        imagejpeg($newImage, null, $this->config['quality']);
                        $content = ob_get_clean();
                        
                        // Réécrire l'image
                        Storage::disk('public')->put($path, $content);
                        $this->copyToPublic($path, $content);
                        
                        imagedestroy($newImage);
                    }

                    // Créer le thumbnail
                    $pathInfo = pathinfo($path);
                    $thumbFilename = $pathInfo['filename'] . '_thumb.' . ($pathInfo['extension'] ?? 'jpg');
                    $thumbPath = $folder . '/thumbnails/' . $thumbFilename;

                    $thumbWidth = $this->config['thumbnail_width'];
                    $thumbHeight = $this->config['thumbnail_height'];
                    $size = min($width, $height);
                    $srcX = (int) (($width - $size) / 2);
                    $srcY = (int) (($height - $size) / 2);

                    $thumbnail = imagecreatetruecolor($thumbWidth, $thumbHeight);
                    imagecopyresampled($thumbnail, $image, 0, 0, $srcX, $srcY, $thumbWidth, $thumbHeight, $size, $size);

                    ob_start();
                    imagejpeg($thumbnail, null, $this->config['quality']);
                    $thumbData = ob_get_clean();

                    Storage::disk('public')->put($thumbPath, $thumbData);
                    $this->copyToPublic($thumbPath, $thumbData);

                    imagedestroy($image);
                    imagedestroy($thumbnail);

                    return [
                        'path' => $path,
                        'thumbnail_path' => $thumbPath
                    ];
                }
            }

            return ['path' => $path, 'thumbnail_path' => null];

        } catch (\Exception $e) {
            Log::error("Erreur migration image {$path}: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Créer une image depuis un chemin
     */
    protected function createImageFromPath(string $path, string $mimeType): ?\GdImage
    {
        try {
            switch ($mimeType) {
                case 'image/jpeg':
                    return imagecreatefromjpeg($path);
                case 'image/png':
                    return imagecreatefrompng($path);
                case 'image/gif':
                    return imagecreatefromgif($path);
                case 'image/webp':
                    if (function_exists('imagecreatefromwebp')) {
                        return imagecreatefromwebp($path);
                    }
                    return null;
                default:
                    return null;
            }
        } catch (\Exception $e) {
            return null;
        }
    }
}
