<?php

namespace AutoAdmin\Bundle\Media\Upload;

use AutoAdmin\Bundle\Content\Site\SiteContextHelper;
use AutoAdmin\Bundle\Core\Upload\FileVerifier;
use AutoAdmin\Bundle\Media\Helper\FileHelper;
use AutoAdmin\Bundle\Media\Library\MediaTypeResolver;
use AutoAdmin\Bundle\Media\Library\MediaPathGenerator;
use AutoAdmin\Bundle\Media\Model\Library\FileMediaInterface;
use AutoAdmin\Bundle\Media\Model\Library\FileMediaTranslationInterface;
use AutoAdmin\Bundle\Media\Model\Library\ImageMediaInterface;
use AutoAdmin\Bundle\Media\Namer\MediaNamer;
use Exception;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class MediaUploadHandler
{
    public function __construct(
        protected MediaNamer $namer,
        protected FileSystem $fileSystem,
        protected SiteContextHelper $siteContext,
        protected string $projectDir,
        protected MediaTypeResolver $typeResolver,
        protected MediaPathGenerator $mediaUrlGenerator,
        protected FileVerifier $verifier,
    ) {
    }

    public function handle(FileMediaInterface $media): bool
    {
        $file = $media->getFile();
        if (null === $file) {
            return false;
        }

        $this->verifier->verify($file);

        /** @var FileMediaTranslationInterface $mediaTrans */
        $mediaTrans = $media->getCurrentTranslation();

        if ($file instanceof UploadedFile) {
            if (
                $media->getId() &&
                $file->getClientOriginalName() !== $media->getOriginalName()
            ) {
                // replacing file
                $this->handleRemove($media);
            }

            // replacement
            if ($media->getId() && $media->getOriginalName()) {
                $this->handleRemove($media, true);
            }

            $media->setOriginalName($file->getClientOriginalName());
            $media->setMimeType($file->getMimeType());
            $media->setSize($file->getSize());

            if ($media instanceof ImageMediaInterface) {
                try {
                    $size = getimagesize($file->getPathname());
                    if (!$size) {
                        $size = [0, 0];
                    }
                } catch (Exception $e) {
                    $size = [0, 0];
                }

                $media->setWidth($size[0]);
                $media->setHeight($size[1]);
            }

            $mediaTrans->setFileName($this->namer->generateName($media->getOriginalName()));
            $media->setExtension(FileHelper::extractExtension($media->getOriginalName()));

            $uploadPath = $this->getUploadPath($media);
            if (!$this->fileSystem->exists($uploadPath)) {
                $this->fileSystem->mkdir($uploadPath);
            }
            $file->move($uploadPath, $mediaTrans->getFileName());
        } elseif ($file instanceof File) {
            // used to programmatically create media (without real uploads)
            $src = $file->getPathname();
            $uploadPath = $this->getUploadPath($media);
            if (!$this->fileSystem->exists($uploadPath)) {
                $this->fileSystem->mkdir($uploadPath);
            }
            $dest = $uploadPath.'/'.$file->getFilename();

            // replacement
            if ($media->getId() && $media->getOriginalName()) {
                $this->handleRemove($media);
            }

            $this->fileSystem->copy($src, $dest);

            $media->setOriginalName($file->getFilename());
            $media->setMimeType($file->getMimeType());
            $media->setSize($file->getSize());
            $media->setFile(null);
            $mediaTrans->setTitle($file->getFilename());
            $mediaTrans->setFileName($file->getFilename());
        }

        return true;
    }

    public function handleRemove(FileMediaInterface $media)
    {
        if (
            empty($media->getCurrentTranslation()->getFileName())
            && empty($media->getOriginalName())
        ) {
            return;
        }

        $uploadPath = $this->getUploadPath($media);
        $filePaths = [
            $uploadPath.'/'.$media->getCurrentTranslation()->getFileName(),
            $uploadPath.'/'.$media->getOriginalName(),
        ];

        foreach ($filePaths as $filePath) {
            if (file_exists($filePath)) {
                unlink($filePath);
            }
        }

    }

    protected function getUploadPath(FileMediaInterface $media): string
    {
        /** @var FileMediaTranslationInterface $trans */
        $trans = $media->getCurrentTranslation();
        $currentSite = $media->getSite();
        if (empty($currentSite)) {
            $currentSite = $this->siteContext->getSite();
        }
        $currentSiteDir = $currentSite->getSlug();

        $typeSlug = $this->typeResolver->getTypeSlug(get_class($media));
        $mappingCfg = $this->typeResolver->getTypeConfig($typeSlug);

        $replace = [
            //'path' => '/public/media/{site_slug}/{type_slug}/{filename}', // (public)
            //'path' => '/var/aa_media/{site_slug}/{type_slug}/{filename}', // (private)
            '{site_slug}' => $currentSiteDir,
            '{type_slug}' => $typeSlug,
            '{filename}' => '',// we want directory, so manually empty last segment
        ];

        $mappingPath = $this->projectDir.$mappingCfg['path'];
        $mappingPath = str_replace(array_keys($replace), array_values($replace), $mappingPath);


        return $mappingPath;
    }
}
