<?php

declare(strict_types=1);

namespace apexl\Io\modules\file\services;

use apexl\Io\modules\file\entities\fileEntity;
use apexl\Io\modules\file\interfaces\FileServiceInterface;
use Mimey\MimeTypes;
use Slim\Psr7\Stream;
use Slim\Psr7\UploadedFile;

class IoFileService implements FileServiceInterface
{
    public function storeFileFromData(string $data, string $directory = 'uploads', ?string $name = null): fileEntity
    {
        $stream = tmpfile();
        fwrite($stream, $data);

        return $this->storeUploadedFile(
            new UploadedFile(
                new Stream($stream),
                $name ?? basename(stream_get_meta_data($stream)['uri'])
            ),
            $directory,
            $name
        );
    }

    public function storeUploadedFile(
        UploadedFile $uploadedFile,
        string $directory = 'uploads',
        ?string $name = null
    ): fileEntity {
        $name = $name ?? sprintf(
            'upload--%s',
            str_replace(' ', '', substr(microtime(), 2))
        );

        $path = File::storeUploadedFile(
            new UploadedFile(
                $uploadedFile->getStream(),
                $name,
            ),
            $directory,
            false
        );

        $mime = $this->mimeFromPath($path);
        $ext = $this->mimeToExt($mime);

        $name = basename($path);
        if (!!$ext && !preg_match(sprintf('/\.%s$/', preg_quote($ext ?? '')), $name)) {
            $name = sprintf('%s.%s', basename($path), $ext);
        }

        $file = new fileEntity();
        $file->name = $name;
        $file->path = $path;
        $file->mime = $mime;
        $file->store();

        return $file;
    }

    private function mimeFromPath(string $path): string
    {
        $mime = mime_content_type($path);

        return match ($mime) {
            'text/xml' => 'application/xml',
            default => $mime,
        };
    }

    public function mimeToExt(string $mime): ?string
    {
        $ext = (new MimeTypes())->getExtension($mime);

        return match ($ext) {
            'jpeg' => 'jpg',
            default => $ext,
        };
    }

    public function copyFileToUploadFolder(
        string $fromPath,
        string $directory = 'uploads',
        ?string $name = null
    ): fileEntity {
        return $this->storeUploadedFile(
            new UploadedFile(
                new Stream(fopen($fromPath, 'r')),
                basename($fromPath)
            ),
            $directory,
            $name
        );
    }
}
