<?php

namespace Modules\Core\Services;

use Intervention\Image\ImageManager;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;

class ImageUpload
{
    protected ImageManager $imageManager;

    public function __construct(ImageManager $imageManager)
    {
        $this->imageManager = $imageManager;
    }

    public function fileExistsInPublic($url, $fileName)
    {
        $filePath = public_path(trim($url, '/') . '/' . $fileName . '.*');
        $files = glob($filePath);

        return !empty($files) ? basename($files[0]) : false;
    }

    public function fileUpload(
        $file = null,
        $data = null,
        $folder = "other",
        $width = 800,
        $height = null,
        $property = 'image',
        $fileName = null,
        $extension = null,
    ) {
        if (!$file && request()->hasFile($property)) {
            $file = request()->file($property);
        }

        if (!$file) {
            return null;
        }

        if (is_string($file)) {
            $file = $this->convertAndSaveBase64($file, $fileName);
        }

        if (!($file instanceof UploadedFile)) {
            throw new \InvalidArgumentException('Unsupported file type.');
        }

        $url = "storage/{$folder}/";
        $path = public_path($url);

        if(!$extension) {
            $extension = Str::startsWith($file->getMimeType(), 'image/') ? ".jpg" : "." . $file->getClientOriginalExtension();
        }

        $finalFileName = $fileName ?? "{$property}_" . time() . "_" . rand(1000, 9999) . $extension;
        
        if (!File::exists($path)) {
            File::makeDirectory($path, 0755, true, true);
        }

        if ($data && isset($data->$property) && !empty($data->$property)) {
            $oldPath = public_path($data->$property);
            if (File::exists($oldPath)) {
                @unlink($oldPath);
            }
        }

        $this->saveFile($file, $width, $height, $path, $finalFileName);

        if ($data) {
            $data->$property = $url . $finalFileName;
            $data->save();
        }

        return $url . $finalFileName;
    }

    protected function saveFile($file, $width, $height, $path, $fileName)
    {
        if ($file->isValid() && Str::startsWith($file->getMimeType(), 'image/')) {
            try {
                $this->imageManager->read($file)
                    ->scale(width: $width, height: $height)
                    ->save($path . $fileName);
            } catch (\Throwable $th) {
                File::put($path . $fileName, file_get_contents($file));
            }
        } else {
            File::put($path . $fileName, file_get_contents($file));
        }
    }

    protected function convertAndSaveBase64($base64String, $filename)
    {
        $fileData = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $base64String));
        $tempFilePath = tempnam(sys_get_temp_dir(), 'img');
        file_put_contents($tempFilePath, $fileData);

        return new UploadedFile($tempFilePath, $filename ?? 'upload.jpg', null, null, true);
    }

    public function uploadFile($file, $property = null, $folder = null)
    {
        $url = "storage/uploads/{$property}/{$folder}/";
        $path = public_path($url);

        if (!File::exists($path)) {
            File::makeDirectory($path, 0755, true, true);
        }

        $extension = "." . $file->getClientOriginalExtension();
        $uniqueName = "{$property}_" . time() . "_" . rand(1000, 9999);
        $fileName = $uniqueName . $extension;

        $file->move($path, $fileName);

        return [
            "name" => $uniqueName,
            "file_name" => $fileName,
            "mime_type" => $file->getClientMimeType(),
            "size" => $this->formatFileSize($file->getSize()),
            "conversions_disk" => "public",
            "thumbnail" => "",
            "file_type" => $file->getClientOriginalExtension(),
        ];
    }

    private function formatFileSize($size)
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        for ($i = 0; $size > 1024 && $i < count($units) - 1; $i++) $size /= 1024;
        return round($size, 2) . ' ' . $units[$i];
    }

    public function deleteFileIfExists($folder = "empty", $fileName, $extension = null)
    {
        $url = "storage/{$folder}/";
        $fullPath = public_path($url . $fileName . ($extension ?? '.*'));

        if ($extension) {
            if (File::exists($fullPath)) {
                return @unlink($fullPath);
            }
        } else {
            $files = glob($fullPath);
            if (!empty($files)) {
                return @unlink($files[0]);
            }
        }
        return false;
    }
}
