<?php

namespace Lucent\File;

use DirectoryIterator;
use Exception;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Http\UploadedFile;
use Illuminate\Log\Logger;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\Drivers\Imagick\Encoders\WebpEncoder;
use Intervention\Image\ImageManager;
use Lucent\Channel\ChannelService;
use Lucent\Database\Database;
use Lucent\LucentException;
use Lucent\Record\FileData as RecordFile;
use Lucent\Record\QueryRecord;
use Lucent\Schema\FilesSchema;
use Lucent\Schema\Schema;
use Spatie\ImageOptimizer\OptimizerChainFactory;
use Symfony\Component\Finder\Finder;

class FileService
{

    public function __construct(
        public ChannelService $channelService,
        public ImageManager   $imageManager,
        public Logger         $logger
    )
    {
    }

    public function getPath(QueryRecord $file): string
    {
        return $this->channelService->channel->filesUrl . "/" . $file->_file->path;
    }

    public function createFromUrl(FilesSchema $schema, string $url): FileUploadResult
    {
        $pathinfo = pathinfo($url);
        $contents = file_get_contents($url);
        if ($contents === false) {
            throw new LucentException("Failed to upload file from url");
        }
        $file = '/tmp/' . $pathinfo['basename'];
        file_put_contents($file, $contents);
        $uploadedFile = new UploadedFile($file, $pathinfo['basename']);
        return $this->upload($schema, $uploadedFile);
    }

    public function upload(FilesSchema $schema, UploadedFile $file): FileUploadResult
    {
        $originalName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
        $extension = pathinfo($file->getClientOriginalName(), PATHINFO_EXTENSION);
        $originalFilename = $file->getClientOriginalName();
        $filename = $this->createFileName($originalName, $extension);
        $mimetype = $file->getMimeType();

        $optimizerChain = OptimizerChainFactory::create();
        $optimizerChain->setTimeout(30)->optimize($file->getPathName());

        $checksum = sha1_file($file);
        $recordId = $this->checkDuplicate($schema->name, $checksum, $file->getSize());

        if (!empty($recordId)) {
            return new FileUploadResult(
                recordFile: null,
                duplicateId: $recordId,
                isDuplicate: true
            );
        }
        $disk = $this->loadDisk($schema);
        $path = $schema->path . "/" . $filename;
        $res = $disk->put(
            $path,
            file_get_contents($file),
//        'public' // now managed by aws policy
        );

        if ($res === false) {
            throw new LucentException("File $filename not uploaded");
        }

        if($this->isImage($mimetype)){
            $this->createTemplates($disk, $path);
        }

        list($width, $height) = $this->isImage($mimetype) ? getimagesize($file) : [0, 0];




        $recordFile = new RecordFile(
            originalName: $originalFilename,
            mime: $mimetype,
            path: $path,
            disk: $schema->disk,
            size: $file->getSize(),
            width: $width,
            height: $height,
            checksum: $checksum
        );

        return new FileUploadResult(
            recordFile: $recordFile,
            duplicateId: "",
            isDuplicate: false
        );
    }

    private function createFileName(string $originalName, string $extension): string
    {
        return Str::slug($originalName, '-') . '-' . uniqid() . '.' . $extension;
    }

    private function isImage(string $mimetype): bool
    {
        $imageMimes = ['image/webp', 'image/gif', 'image/jpeg', 'image/png', 'image/tiff'];
        return in_array($mimetype, $imageMimes);
    }

    public function loadDisk(Schema|string $schema): Filesystem
    {
        return Storage::disk($schema->disk ?? $schema);

    }

    private function checkDuplicate(string $schemaName, string $checksum, int $filesize): string
    {

        $record = Database::make()->table("records")
            ->where("schema", $schemaName)
            ->where("_file->checksum", $checksum)
            ->where("_file->size", $filesize)
            ->first();

        return $record->id ?? "";
    }

    public function createTemplates(Filesystem $disk, string $path): void
    {
        try {
            $originalImage = $this->imageManager->read($disk->get($path));
        }catch (Exception $exception){
            $this->logger->error($exception->getMessage());
            return;
        }

        foreach (new DirectoryIterator(config("lucent.image_filters_path")) as $file) {
            if($file->isDot()) continue;

            $namespace = app()->getNamespace();
            $filterClass = $namespace.str_replace(
                ['/', '.php'],
                ['\\', ''],
                Str::after($file->getRealPath(), realpath(app_path()).DIRECTORY_SEPARATOR)
            );

            $image = $originalImage->modify(new $filterClass);
            $templateUri = "/templates/" . (new $filterClass)->name . "/" . $path;
            $disk->put($templateUri, $image->encode(new WebpEncoder(75)));
        };


        $thumbDir = "thumbs/" . $path;

        $image = $originalImage->cover(300, 300);
        $disk->put($thumbDir, $image->encode(new WebpEncoder(quality: 75)));
    }
}
