<?php

namespace App\Traits;

use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\Laravel\Facades\Image;
use Log;

trait ImageTrait
{
    /**
     * Upload a file to s3 / wasabi / do with public visibility.
     */
    protected function putFileOnCloudDisk(string $storageSetting, string $key, string $absoluteLocalPath, string $contentType): bool
    {
        $disk = storage_disk_for_setting($storageSetting);
        if ($disk === null) {
            return false;
        }
        $opts = ['visibility' => 'public', 'ContentType' => $contentType];

        return Storage::disk($disk)->put(ltrim($key, '/'), file_get_contents($absoluteLocalPath), $opts);
    }

    protected function guessContentTypeFromExtension(string $extension): string
    {
        $extension = strtolower($extension);

        return match ($extension) {
            'jpg', 'jpeg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif',
            'webp' => 'image/webp',
            'svg' => 'image/svg+xml',
            default => 'application/octet-stream',
        };
    }

    public function saveImage($requestImage, $for = '_product_', $save_to_db = false, $url = null, $token_id = null)
    {
        $extension = 'png';
        $mime_type = 'image/png';
        if ((!empty($requestImage) && $requestImage != 'null') || $url) {
            
            if (!$url) {
                $image = explode('.', $requestImage->getClientOriginalName());
                $extension = strtolower($requestImage->getClientOriginalExtension());
                $name = $image[0];
                // $mime_type = $requestImage->getMimeType();
                $mime_type = strtolower($requestImage->getClientOriginalExtension());
            }
            
            $storage = setting('default_storage') ?: 'local';
            $response = false;
            
            
            $content_type = ['visibility' => 'public', 'ContentType' => $extension == 'svg' ? 'image/svg+xml' : $mime_type];
            $encode_percentage = $this->getEncodePercentage();
            
            $directory = 'uploads/' . trim($for, '_') . 's/';
            
            $directoryPath = public_path($directory);
            // Ensure directory exists
            if (!File::exists($directoryPath)) {
                File::makeDirectory($directoryPath, 0755, true);
            }

            if ($for === 'favicon' || $for === 'admin_favicon') {


                $fileType = $requestImage->getClientOriginalExtension();

                $originalImage = date('YmdHis') . "-" . $for . rand(1, 500) . '.' . $fileType;
                $image_16x16 = date('YmdHis') . "-" . $for . '-16x16-' . rand(1, 500) . '.' . $fileType;
                $image_32x32 = date('YmdHis') . "-" . $for . '-32x32-' . rand(1, 500) . '.' . $fileType;
                $image_57x57 = date('YmdHis') . "-" . $for . '-57x57-' . rand(1, 500) . '.' . $fileType;
                $image_60x60 = date('YmdHis') . "-" . $for . '-60x60-' . rand(1, 500) . '.' . $fileType;
                $image_72x72 = date('YmdHis') . "-" . $for . '-72x72-' . rand(1, 500) . '.' . $fileType;
                $image_76x76 = date('YmdHis') . "-" . $for . '-76x76-' . rand(1, 500) . '.' . $fileType;
                $image_96x96 = date('YmdHis') . "-" . $for . '-96x96-' . rand(1, 500) . '.' . $fileType;
                $image_114x114 = date('YmdHis') . "-" . $for . '-114x114-' . rand(1, 500) . '.' . $fileType;
                $image_120x120 = date('YmdHis') . "-" . $for . '-120x120-' . rand(1, 500) . '.' . $fileType;
                $image_144x144 = date('YmdHis') . "-" . $for . '-144x144-' . rand(1, 500) . '.' . $fileType;
                $image_152x152 = date('YmdHis') . "-" . $for . '-152x152-' . rand(1, 500) . '.' . $fileType;
                $image_180x180 = date('YmdHis') . "-" . $for . '-180x180-' . rand(1, 500) . '.' . $fileType;
                $image_192x192 = date('YmdHis') . "-" . $for . '-192x192-' . rand(1, 500) . '.' . $fileType;

                // $directory = 'images/icon/';
                // File::ensureDirectoryExists($directoryPath.$directory, 0777, true);

                $originalImageUrl = $directory . $originalImage;
                $image_16x16_url = $directory . $image_16x16;
                $image_32x32_url = $directory . $image_32x32;
                $image_57x57_url = $directory . $image_57x57;
                $image_60x60_url = $directory . $image_60x60;
                $image_72x72_url = $directory . $image_72x72;
                $image_76x76_url = $directory . $image_76x76;
                $image_96x96_url = $directory . $image_96x96;
                $image_114x114_url = $directory . $image_114x114;
                $image_120x120_url = $directory . $image_120x120;
                $image_144x144_url = $directory . $image_144x144;
                $image_152x152_url = $directory . $image_152x152;
                $image_180x180_url = $directory . $image_180x180;
                $image_192x192_url = $directory . $image_192x192;

                $originalRel = 'images/' . $originalImage;
                $faviconCt = $this->guessContentTypeFromExtension($fileType);

                if ($storage === 'local') {
                    copy($requestImage->getRealPath(), public_path($originalRel));

                    Image::read($requestImage)->resize(16, 16, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_16x16_url, $encode_percentage);

                    Image::read($requestImage)->resize(32, 32, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_32x32_url, $encode_percentage);
                    Image::read($requestImage)->resize(57, 57, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_57x57_url, $encode_percentage);
                    Image::read($requestImage)->resize(60, 60, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_60x60_url, $encode_percentage);
                    Image::read($requestImage)->resize(72, 72, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_72x72_url, $encode_percentage);
                    Image::read($requestImage)->resize(76, 76, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_76x76_url, $encode_percentage);
                    Image::read($requestImage)->resize(96, 96, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_96x96_url, $encode_percentage);
                    Image::read($requestImage)->resize(114, 114, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_114x114_url, $encode_percentage);
                    Image::read($requestImage)->resize(120, 120, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_120x120_url, $encode_percentage);
                    Image::read($requestImage)->resize(144, 144, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_144x144_url, $encode_percentage);
                    Image::read($requestImage)->resize(152, 152, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_152x152_url, $encode_percentage);
                    Image::read($requestImage)->resize(180, 180, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_180x180_url, $encode_percentage);
                    Image::read($requestImage)->resize(192, 192, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(isLocalhost() . $image_192x192_url, $encode_percentage);
                } else {
                    $tmpDir = storage_path('app/temp/' . (string) Str::uuid());
                    File::ensureDirectoryExists($tmpDir, 0755, true);
                    try {
                        $origTmp = $tmpDir . DIRECTORY_SEPARATOR . 'orig.' . $fileType;
                        File::copy($requestImage->getRealPath(), $origTmp);
                        $this->putFileOnCloudDisk($storage, $originalRel, $origTmp, $faviconCt);

                        $faviconVariants = [
                            [$image_16x16_url, 16, 16],
                            [$image_32x32_url, 32, 32],
                            [$image_57x57_url, 57, 57],
                            [$image_60x60_url, 60, 60],
                            [$image_72x72_url, 72, 72],
                            [$image_76x76_url, 76, 76],
                            [$image_96x96_url, 96, 96],
                            [$image_114x114_url, 114, 114],
                            [$image_120x120_url, 120, 120],
                            [$image_144x144_url, 144, 144],
                            [$image_152x152_url, 152, 152],
                            [$image_180x180_url, 180, 180],
                            [$image_192x192_url, 192, 192],
                        ];
                        foreach ($faviconVariants as $idx => [$relPath, $w, $h]) {
                            $out = $tmpDir . DIRECTORY_SEPARATOR . 'v' . $idx . '.' . $fileType;
                            Image::read($requestImage)->resize((int) $w, (int) $h, function ($constraint) {
                                $constraint->aspectRatio();
                            })->save($out, $encode_percentage);
                            $this->putFileOnCloudDisk($storage, $relPath, $out, $faviconCt);
                        }
                    } finally {
                        File::deleteDirectory($tmpDir);
                    }
                }

                $images = array(
                    'storage' => $storage,
                    'original_image' => 'images/' . $originalImage,
                    'image_16x16_url' => $image_16x16_url,
                    'image_32x32_url' => $image_32x32_url,
                    'image_57x57_url' => $image_57x57_url,
                    'image_60x60_url' => $image_60x60_url,
                    'image_72x72_url' => $image_72x72_url,
                    'image_76x76_url' => $image_76x76_url,
                    'image_96x96_url' => $image_96x96_url,
                    'image_114x114_url' => $image_114x114_url,
                    'image_120x120_url' => $image_120x120_url,
                    'image_144x144_url' => $image_144x144_url,
                    'image_152x152_url' => $image_152x152_url,
                    'image_180x180_url' => $image_180x180_url,
                    'image_192x192_url' => $image_192x192_url,
                );
            } else {

                File::ensureDirectoryExists($directory, 0777, true);
                $originalImage = date('YmdHis') . '_original_' . $for . rand(1, 500) . '.' . $extension;
                $image_240x240 = date('YmdHis') . 'image_240x240' . $for . rand(1, 500) . '.' . $extension;
                $image_240x240_url = $directory . $image_240x240;
                $image_80x80 = date('YmdHis') . 'image_80x80' . $for . rand(1, 500) . '.' . $extension;
                $image_80x80_url = $directory . $image_80x80;
                $image_1080x720 = date('YmdHis') . 'image_1080x720' . $for . rand(1, 500) . '.' . $extension;
                $image_1080x720_url = $directory . $image_1080x720;
                $originalRelative = 'images/' . $originalImage;
                $contentType = $this->guessContentTypeFromExtension($extension);

                if ($storage === 'local') {
                    copy($requestImage->getRealPath(), public_path($originalRelative));

                    Image::read($requestImage)->resize(240, 240, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(public_path($image_240x240_url), $encode_percentage);

                    Image::read($requestImage)->resize(80, 80, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(public_path($image_80x80_url), $encode_percentage);

                    Image::read($requestImage)->resize(1080, 720, function ($constraint) {
                        $constraint->aspectRatio();
                    })->save(public_path($image_1080x720_url), $encode_percentage);
                } else {
                    $tmpDir = storage_path('app/temp/' . (string) Str::uuid());
                    File::ensureDirectoryExists($tmpDir, 0755, true);
                    try {
                        $origTmp = $tmpDir . DIRECTORY_SEPARATOR . 'orig.' . $extension;
                        File::copy($requestImage->getRealPath(), $origTmp);
                        $this->putFileOnCloudDisk($storage, $originalRelative, $origTmp, $contentType);

                        $variants = [
                            [$image_240x240_url, 240, 240],
                            [$image_80x80_url, 80, 80],
                            [$image_1080x720_url, 1080, 720],
                        ];
                        foreach ($variants as [$relPath, $w, $h]) {
                            $out = $tmpDir . DIRECTORY_SEPARATOR . str_replace(['/', '\\'], '_', $relPath);
                            Image::read($requestImage)->resize((int) $w, (int) $h, function ($constraint) {
                                $constraint->aspectRatio();
                            })->save($out, $encode_percentage);
                            $this->putFileOnCloudDisk($storage, $relPath, $out, $contentType);
                        }
                    } finally {
                        File::deleteDirectory($tmpDir);
                    }
                }

                $images = [
                    'storage' => $storage,
                    'original_image' => $originalRelative,
                    'image_240x240' => $image_240x240_url,
                    'image_80x80' => $image_80x80_url,
                    'image_1080x720' => $image_1080x720_url,
                ];
            }


            $data['images'] = $images;
            $data['id'] = isset($media) ? $media->id : null;

            return $data;
        } else {
            return false;
        }
    }
    //for configuration only
    public function deleteImage($files, $storage = 'local')
    {
        try {
            // dd($files);

            foreach (array_slice($files, 1) as $key => $file) {
                // Replace path only if it's the original image
                if (Str::contains($key, 'original_image')) {
                    // Replace only the first segment from 'uploads/{any_folder}/' to 'images/'
                    $file = preg_replace('#^uploads/[^/]+/#', 'images/', $file);
                }
                if ($storage == 'aws_s3') {
                    Storage::disk('s3')->delete($file);
                } elseif ($storage == 'wasabi') {
                    Storage::disk('wasabi')->delete($file);
                } elseif ($storage == 'do') {
                    Storage::disk('do')->delete($file);
                } else {
                    $fullPath = public_path($file); // Resolves to full file system path
                    if (File::exists($fullPath)) {
                        File::delete($fullPath);
                    } else {
                        Log::warning("File not found: $fullPath");
                    }
                }
            }
            return true;
        } catch (\Exception $e) {
            Log::error('Error deleting image: ' . $e->getMessage());
            return false;
        }
    }

    //for other images like blog, movie, etc.
    public function imageDelete($id, $model, $column)
    { // id of model, model name, column name
        $modelClass = '\\App\\Models\\' . ucfirst($model); // adjust namespace if needed
        $query = $modelClass::where('id', $id)->first();

        if (!$query) {
            return response()->json(['error' => 'Model not found'], 404);
        }

        $images = json_decode($query->$column, true);

        if (! is_array($images)) {
            $query->$column = null;
            $query->save();

            return response()->json(['success' => 'Images deleted from all folders']);
        }

        $stor = $images['storage'] ?? 'local';

        if ($stor === 'local') {
            foreach ($images as $key => $path) {
                if ($key === 'storage') {
                    continue;
                }
                $originalPath = public_path($path);
                if (File::exists($originalPath)) {
                    File::delete($originalPath);
                }

                $pathParts = explode('/', $path);
                if (count($pathParts) > 1) {
                    $fileName = end($pathParts);
                    $duplicatePath = public_path('images/' . $fileName);
                    if (File::exists($duplicatePath)) {
                        File::delete($duplicatePath);
                    }
                }
            }
        } elseif (in_array($stor, ['aws_s3', 'wasabi', 'do'], true)) {
            $disk = storage_disk_for_setting($stor);
            if ($disk) {
                foreach ($images as $key => $path) {
                    if ($key === 'storage' || $path === '' || $path === null) {
                        continue;
                    }
                    if (Str::contains((string) $key, 'original_image')) {
                        $path = preg_replace('#^uploads/[^/]+/#', 'images/', $path);
                    }
                    Storage::disk($disk)->delete(ltrim($path, '/'));
                }
            }
        }

        $query->$column = null;
        $query->save();

        return response()->json(['success' => 'Images deleted from all folders']);
    }

    public function saveFile($requested_file, $type, $save_to_db = true)
    {
        if (!empty($requested_file) && $requested_file != 'null') {
            $image = explode('.', $requested_file->getClientOriginalName());
            $extension = $requested_file->getClientOriginalExtension();
            $name = $image[0];
            $size = @$requested_file->getSize();
            $storage = setting('default_storage') ?: 'local';
            $response = false;
            $mime_type = $requested_file->getMimeType();
            // dd($mime_type);
            $content_type = ['visibility' => 'public', 'ContentType' => $extension == 'svg' ? 'image/svg+xml' : $mime_type];
            $originalFile = date('YmdHis') . '_original_' . rand(1, 500) . '.' . $extension;
            $directory = 'files/';

            $originalFileUrl = $directory . $originalFile;
            $mimeForPut = $extension == 'svg' ? 'image/svg+xml' : $mime_type;

            if ($storage === 'local') {
                File::ensureDirectoryExists(public_path($directory), 0777, true);
                $requested_file->move(public_path($directory), $originalFile);
            } else {
                if (! $this->putFileOnCloudDisk($storage, $originalFileUrl, $requested_file->getRealPath(), $mimeForPut)) {
                    return match ($storage) {
                        'aws_s3' => 's3_error',
                        'do' => 'do_error',
                        default => 'wasabi_error',
                    };
                }
            }

            if ($type == 'pos_file') {
                return ['storage' => $storage, 'image' => $originalFileUrl];
            }

            return $originalFileUrl;
        } else {
            return false;
        }
    }

    public function deleteFile($file, $storage = 'local')
    {
        try {
            if ($storage == 'aws_s3') {
                Storage::disk('s3')->delete($file);
            } elseif ($storage == 'wasabi') {
                Storage::disk('wasabi')->delete($file);
            } elseif ($storage == 'do') {
                Storage::disk('do')->delete($file);
            } else {
                $path = public_path($file);
                if (File::exists($path)) {
                    File::delete($path);
                }
            }

            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    public function getImage($id)
    {
        $image = MediaLibrary::find($id);
        if (!blank($image)) {
            $data = $image->image_variants;

            return $data;
        } else {
            return false;
        }
    }

    protected function uploadToS3($files, $contentType)
    {
        foreach (array_slice($files, 1) as $file) {
            if ($file != '') {
                $filePath = $file;

                if (file_exists($filePath)) {
                    $uploadSuccess = Storage::disk('s3')->put($file, file_get_contents($filePath), $contentType);

                    if ($uploadSuccess) {
                        // Optional: Log success or perform additional actions
                        dd('File uploaded successfully to S3: ' . $file);
                    } else {
                        dd('Failed to upload file to S3: ' . $file);
                    }
                } else {
                    dd('File does not exist: ' . $filePath);
                }
            }
        }

        return true;
    }

    protected function uploadToDO($files, $contentType)
    {
        $directory = setting('do_directory') ? setting('do_directory') . '/' : '';
        foreach (array_slice($files, 1) as $file) {
            if ($file != '' && file_exists(public_path('/') . $file)) {
                $file_content = file_get_contents(public_path('/') . $file);
                Storage::disk('do')->put($directory . $file, $file_content, $contentType);
            }
        }

        return true;
    }

    protected function uploadFileToDO($file, $contentType)
    {
        if ($file != '' && file_exists(public_path('/') . $file)) {
            Storage::disk('do')->put($file, file_get_contents(public_path('/') . $file), $contentType);

            return true;
        }

        return false;
    }

    protected function uploadFileToS3($file, $contentType)
    {
        if ($file != '' && file_exists('public/' . $file)) {
            Storage::disk('s3')->put($file, file_get_contents('public/' . $file), $contentType);

            return true;
        }

        return false;
    }

    protected function uploadToWasabi($files, $contentType)
    {

        // Check if the $files is an array
        if (!is_array($files)) {
            throw new \InvalidArgumentException('The $files parameter must be an array.');
        }

        // Loop through each file
        foreach (array_slice($files, 1) as $file) {
            // Ensure the file path is not empty
            if ($file != '' && file_exists(public_path($file))) {
                try {
                    // Read the file contents
                    $fileContents = file_get_contents(public_path($file));

                    // Upload the file to Wasabi
                    $result = Storage::disk('wasabi')->put($file, $fileContents, ['ContentType' => $contentType]);

                    // Log the result for debugging
                    if (!$result) {
                        dd("Failed to upload file: $file");
                        \Log::warning("Failed to upload file: $file");
                    }
                } catch (\Exception $e) {
                    dd($e->getMessage());
                    \Log::error("Error uploading file to Wasabi: {$e->getMessage()}");
                }
            } else {
                dd("File does not exist: $file");
                \Log::warning("File does not exist: $file");
            }
        }

        return true;
    }

    protected function uploadFileToWasabi($file, $contentType)
    {
        if ($file != '' && file_exists('public/' . $file)) {
            Storage::disk('wasabi')->put($file, file_get_contents('public/' . $file), $contentType);

            return true;
        }

        return false;
    }

    public function getImageWithRecommendedSize($width, $height, $image)
    {

        $extension = strtolower($image->getClientOriginalExtension());
        $directory = 'images/';

        $originalImage = date('YmdHis') . '-user-' . rand(1, 500) . '.' . $extension;
        $image20X20 = date('YmdHis') . 'image_20X20-user-' . rand(1, 500) . '.' . $extension;

        $originalImageUrl = $directory . $originalImage;
        $image20X20Url = $directory . $image20X20;

        Image::make($image)->save(isLocalhost() . $originalImageUrl);

        Image::make($image)->resize(
            $width,
            $height,
            function ($constraint) {
                $constraint->aspectRatio();
            }
        )->save(isLocalhost() . $image20X20Url);

        $images = [
            'original_image' => $originalImageUrl,
            'image_20x20' => $image20X20Url,
        ];

        $data['images'] = $images;
        $data['id'] = null;

        return $data;
    }

    public function getImageArrayRecommendedSize($id, $widths = [], $heights = [])
    {
        foreach ($widths as $key => $width) {
            $height = $heights[$key];
            $this->getImageWithRecommendedSize($id, $width, $height);
        }
    }

    protected function getEncodePercentage(): int
    {
        if (setting('image_optimization') && setting('image_optimization') == 0) {
            $encode_percentage = setting('image_optimization_percentage') ?: 90;
        } else {
            $encode_percentage = 90;
        }

        return $encode_percentage;
    }

    public function saveMultipleImage($images, $product): array
    {
        $storage = setting('default_storage') ?: 'local';

        $description_images = [];
        if ($images && count($images) > 0) {
            if ($product && $product->description_images && count($product->description_images)) {
                foreach ($product->description_images as $description_image) {
                    $this->deleteFile($description_image['image'], $storage);
                }
            }
            foreach ($images as $description_image) {
                $image_name = Str::uuid() . '.' . $description_image->getClientOriginalExtension();
                $path = "images/description_images/$image_name";
                $ct = $this->guessContentTypeFromExtension($description_image->getClientOriginalExtension());
                if ($storage === 'local') {
                    File::ensureDirectoryExists(public_path('images/description_images'), 0755, true);
                    $description_image->move(public_path('images/description_images'), $image_name);
                } else {
                    if (! $this->putFileOnCloudDisk($storage, $path, $description_image->getRealPath(), $ct)) {
                        continue;
                    }
                }
                $description_images[] = [
                    'image' => $path,
                    'storage' => $storage,
                ];
            }
        }

        if (count($description_images) == 0 && $product && $product->description_images) {
            $description_images = $product->description_images;
        }

        return $description_images;
    }

    public function saveFont($requested_file)
    {
        if (!empty($requested_file) && $requested_file != 'null') {
            $image = explode('.', $requested_file->getClientOriginalName());
            $extension = $requested_file->getClientOriginalExtension();
            $name = $image[0];
            $size = @$requested_file->getSize();
            $storage = setting('default_storage') ?: 'local';
            $response = false;
            $mime_type = $requested_file->getMimeType();
            $content_type = ['visibility' => 'public', 'ContentType' => $extension == 'svg' ? 'image/svg+xml' : $mime_type];
            $originalFile = date('YmdHis') . '_original_' . rand(1, 500) . '.' . $extension;
            $directory = 'fonts/';

            $originalFileUrl = $originalFile;
            $fontKey = $directory . $originalFileUrl;
            $mimeForPut = $extension == 'svg' ? 'image/svg+xml' : $mime_type;

            if ($storage === 'local') {
                File::ensureDirectoryExists(resource_path($directory), 0777, true);
                $requested_file->move(resource_path($directory), $originalFileUrl);
            } else {
                if (! $this->putFileOnCloudDisk($storage, $fontKey, $requested_file->getRealPath(), $mimeForPut)) {
                    return match ($storage) {
                        'aws_s3' => 's3_error',
                        'do' => 'do_error',
                        default => 'wasabi_error',
                    };
                }
            }

            return ['storage' => $storage, 'file' => $storage === 'local' ? $originalFileUrl : $fontKey];
        } else {
            return false;
        }
    }
}
