<?php

namespace Internetgalerie\IgDatapoolFe\Property\TypeConverter;

use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Core\Utility\MathUtility;
use Internetgalerie\IgDatapoolFe\Services\LangService;
use Internetgalerie\IgDatapoolFe\Controller\ActionController;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Extbase\Property\Exception;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;

use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Resource\File as FalFile;
use TYPO3\CMS\Core\Resource\FileReference as FalFileReference;
use TYPO3\CMS\Core\Resource\Security\FileNameValidator;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Error\Error;
use TYPO3\CMS\Extbase\Property\Exception\TypeConverterException;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;

/**
 * Class UploadedObjectStorageFileReferenceConverter
 */
class UploadedObjectStorageFileReferenceConverter extends AbstractTypeConverter
{
    /**
     * @var array<string>
     */
    protected $sourceTypes = ['array'];

    /**
     * @var string
     */
    protected $targetType = 'TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>';//TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>';//Domain\\Model\\FileReference';

    /**
     * Needs to take precedence over the available FileReferenceConverter
     *
     * @var integer
     */
    protected $priority = 2;

    /**
     * @var ResourceFactory
     */
    protected $resourceFactory;

    /**
     * @var HashService
     */
    protected $hashService;

    /**
     * @var PersistenceManager
     */
    protected $persistenceManager;

    /**
     * @var FileInterface[]
     */
    protected $convertedResources = [];

    /**
     * @param ResourceFactory $resourceFactory
     */
    public function injectResourceFactory(ResourceFactory $resourceFactory): void
    {
        $this->resourceFactory = $resourceFactory;
    }

    /**
     * @param HashService $hashService
     */
    public function injectHashService(HashService $hashService): void
    {
        $this->hashService = $hashService;
    }

    /**
     * @param PersistenceManager $persistenceManager
     */
    public function injectPersistenceManager(PersistenceManager $persistenceManager): void
    {
        $this->persistenceManager = $persistenceManager;
    }


    public function log($text): void
    {
        $fp = fopen('/tmp/log.txt', 'a');
        fputs($fp, $text ."\n");
        fclose($fp);
    }
    public function log_var_dump($var): void
    {
        $fp = fopen('/tmp/log.txt', 'a');
        $text = var_export($var, true);
        fputs($fp, 'DUMP[UploadedObjectStorageFileReferenceConverter]=' .  $text ."\n");
        fclose($fp);
    }
    /**
     * Actually convert from $source to $targetType, taking into account the fully
     * built $convertedChildProperties and $configuration.
     *
     * @param  string|integer                                                    $source
     * @param  string                                                            $targetType
     * @param  array                                                             $convertedChildProperties
     * @param PropertyMappingConfigurationInterface $configuration
     * @throws Exception
     * @return \TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder
     * @api
     */
    public function convertFrom($source_in, string $targetType, array $convertedChildProperties = [], PropertyMappingConfigurationInterface $configuration = null): ObjectStorage
    {
        $this->log("INIT UploadedObjectStorageFileReferenceConverter.php");
        /*
           * If we already converted it..
           */
        if (isset($this -> convertedResources[md5(serialize($source_in))])) {
            return $this -> convertedResources[md5(serialize($source_in))];
        }

        /**
         * OK, for my understanding..
         * we have 2 kinds of references:
         * MODEL --> TYPO3\\CMS\\Extbase\\Domain\\Model\\FileReference --> TYPO3\CMS\Core\Resource\FileReference  --> TYPO3\CMS\Core\Resource\File
         */

        $fileReference = null;
        //var_dump($source_in);exit(0);
        //    foreach( $source_in as $source ) {
        $source=$source_in;

        var_dump($source);
        exit(0);


        if ((int)$source['uid']>0 &&  (int)$source['remove']==1) {
            // Delete reference
            $fileReferenceRepository =  GeneralUtility::makeInstance(FileRepository::class);
            $reference =   $fileReferenceRepository->findFileReferenceByUid(intval($source['uid']));
            $fileReferenceRepository->remove($reference);
            return  null;//new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();// NULL;//$reference;//NULL;
        }

        if (isset($source['curFile']) && isset($source['origFilename'])) {
            //echo('img set:'. $source['curFile'] .'='. $source['origFilename'] .'<br />');
            if (str_starts_with((string) $source['origFilename'], 'file:')) {
                // in this case we reference a file object, because the filereference object has not been sotred yet
                $fileId = intval($this -> hashService -> validateAndStripHmac($source['curFile']));
                $fileReference = $this -> createFileReferenceFromFalFileObject($this -> resourceFactory -> getFileObject($fileId));
            } elseif (MathUtility::canBeInterpretedAsInteger($source['origFilename'])) {
                // Here we have a reference ID.. so do nothing, basically ^^
                // make sure no one has tempered with it.
                $fileId = intval($this -> hashService -> validateAndStripHmac($source['curFile']));
                $fileReference = $this -> createFileReferenceFromFalFileReferenceObject($this -> resourceFactory -> getFileReferenceObject($fileId));
            } elseif ($source['curFile']) {
                // it is atemporary string
                $filePath = Environment::getPublicPath() . 'fileadmin/_temp_/' . $source['curFile'];

                // if there was a problem and our source file doesn't exist, we just return NULL
                if (!is_file($filePath)) {
                    return null;
                }
                // check again for php and illegal stuff
                if (!GeneralUtility::makeInstance(FileNameValidator::class)->isValid($source['name'])) {
                    throw new TypeConverterException('Uploading files with PHP file extensions is not allowed!', 1399312430);
                }

                // get the uploaded file object
                $uploadedFile = $this -> resourceFactory -> retrieveFileOrFolderObject($filePath);

                // do the checks here VALIDATION
                $options = $this -> hashService -> validateAndStripHmac($source['options']);
                $options = unserialize(base64_decode($options));
                if (isset($options['maxSize'])) {
                    $size = $uploadedFile -> getSize();
                    if ($size > $options['maxSize'] * 1024) {
                        $uploadedFile -> delete();
                        return new Error(LangService::ll('validator.file.tooBig', 'ig_datapool_fe'), time());
                    }
                }

                if (isset($options['allowedExtensions']) && $options['allowedExtensions'] != '*') {
                    $ext = $uploadedFile -> getExtension();
                    if (!in_array($ext, $options['allowedExtensions'])) {
                        $uploadedFile -> delete();
                        return new Error(LangService::ll('validator.file.invalidType', 'ig_datapool_fe'), time());
                    }
                }

                if (isset($options['minImageSize'])) {
                    $minSize = $options['minImageSize'];
                    if (stripos((string) $minSize, 'mp')) {
                        $minSize = floatval($minSize) * (1024 * 1024);
                    } else {
                        $minSize = floatval($minSize);
                    }

                    $size = getimagesize($uploadedFile -> getForLocalProcessing(false));

                    $fullSize = $size[0] * $size[1];
                    if ($fullSize > 0 && $fullSize < $minSize) {
                        $uploadedFile -> delete();
                        return new Error(LangService::ll('validator.image.tooSmall', 'ig_datapool_fe'), time());
                    }
                }

                // create upload folder
                $uploadFolder = $this -> resourceFactory -> retrieveFileOrFolderObject('1:/');
                $request = ActionController::$currentController -> getRequest();

                // move to fileadmin/datapool_upload/extension/controller/origFilename.jpg
                $folderName = 'datapool_upload/' . $request -> getControllerExtensionName() . '/' . $request -> getControllerName();
                $uploadFolder = $uploadFolder -> createFolder($folderName);

                // rename and move
                $uploadedFile = $uploadedFile -> rename($source['origFilename']) -> moveTo($uploadFolder, null, 'renameNewFile');

                $fileReference = $this -> createFileReferenceFromFalFileObject($uploadedFile);

                //store it for later use..
                $this -> convertedResources[md5(serialize($source))] = $fileReference;
            } else {
                //Delete, remove the uid of our reference
                //var_dump($source['uid']);exit(0);
                return null;
            }
        }
        //    }
        //var_dump($source);exit(0);
        return count($fileReference);
    }

    /**
     * @param  FalFile $file
     * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference
     */
    protected function createFileReferenceFromFalFileObject(FalFile $file)
    {
        //$fileReference = $this -> resourceFactory -> createFileReferenceObject(array('uid_local' => $file -> getUid(), 'uid_foreign' => uniqid('NEW_'), 'uid' => uniqid('NEW_'), ));
        $fileReference = GeneralUtility::makeInstance(FalFileReference::class, ['uid_local' => $file -> getUid(), 'uid_foreign' => uniqid('NEW_'), ]);
        //$this -> resourceFactory -> getFileReferenceObject(array('uid_local' => $file -> getUid(), 'uid_foreign' => uniqid('NEW_'), 'uid' => uniqid('NEW_'), ));
        return $this -> createFileReferenceFromFalFileReferenceObject($fileReference);
    }

    /**
     * @param  FalFileReference $falFileReference
     * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference
     */
    protected function createFileReferenceFromFalFileReferenceObject(FalFileReference $falFileReference)
    {
        $fileReference = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Domain\Model\FileReference::class);
        $fileReference->setOriginalResource($falFileReference);
        return $fileReference;
    }
}
