<?php

namespace Internetgalerie\IgDatapoolFe\Property\TypeConverter;

use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
use Internetgalerie\IgDatapoolFe\Domain\Repository\FileReferenceRepository;
use Internetgalerie\IgDatapoolFe\Utility\FormUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Extbase\Property\Exception;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\StringUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;

/**
 * Class FileReferenceConverter
 */
class FileReferenceConverter extends AbstractTypeConverter
{
    protected $debug = false;
    protected $debugLog='/tmp/log2.txt';

    /**
     * @var array<string>
     */
    protected $sourceTypes = [ 'array' ];

    /**
     * @var string
     */
    protected $targetType = FileReference::class;

    /**
     * Needs to take precedence over the available FileReferenceConverter (also the one from sf_register in UploadedFileReferenceConverter.php)
     *
     * @var integer
     */
    protected $priority = 32;

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

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

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

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

    /**
     * @var FileReferenceRepository
     */
    protected $fileReferenceRepository = null;


    /**
     * @var FormUtility
     */
    protected $formUtility;


    protected $fileFactory;

    public function injectFileFactory(ResourceFactory $fileFactory): void
    {
        $this->fileFactory = $fileFactory;
    }



    public function __construct()
    {
        $this->resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
        $this->hashService = GeneralUtility::makeInstance(HashService::class);
        $this->fileReferenceRepository = GeneralUtility::makeInstance(FileReferenceRepository::class);
        $this->persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class);
        $this->formUtility = GeneralUtility::makeInstance(FormUtility::class);
    }

    public function log($text): void
    {
        $fp = fopen($this->debugLog, 'a');
        fputs($fp, $text ."\n");
        fclose($fp);
    }
    public function log_var_dump($var): void
    {
        $fp = fopen($this->debugLog, 'a');
        //ob_start();      var_dump($var);      $text = ob_get_clean();
        $text = var_export($var, true);
        fputs($fp, 'File-DUMP[FileReferenceConverter]=' .  $text ."\n");
        fclose($fp);
    }


    /**
     *  nicht bei Extension SYSEXT: from konvertieren
     * @todo verbessern - nur bei vorhanden sein von __dpInlineFields und __dpUploadFal und __dpUploadFileReferences
     */
    public function canConvertFrom($source, string $targetType): bool
    {
        foreach ($_POST as $name=>$val) {
            if ($name == 'tx_form_formframework') {
                return false;
            }
        }
        if ($this->debug) {
            $this->log('canConvertFrom FileReferenceConverter');
        }
        return true;
    }
    /**
     * 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, string $targetType, array $convertedChildProperties = [], PropertyMappingConfigurationInterface $configuration = null): ?FileReference
    {
        /**
         * If we already converted it..
         */
        if ($this->debug) {
            $this->log("\n-----------------------------------------------------\nINIT: FileReferenceConverter.php");
        }
        if (isset($this->convertedResources[md5(serialize($source))])) {
            return $this->convertedResources[md5(serialize($source))];
        }

        /**
         * 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;
        $fileReferenceUid = null;

        if ($this->debug) {
            $this->log_var_dump($source);
        }
        if (isset($source['__identity'])) {
            $fileReferenceUid = intval($source['__identity']);
            if ($this->debug) {
                $this->log('__identity='. $fileReferenceUid);
            }
            if ($fileReferenceUid > 0) {
                //$fileReference = $this->fileReferenceRepository->findByUid($fileReferenceUid);
                $fileReferenceObject = $this->fileFactory->getFileReferenceObject($fileReferenceUid);
                if ($fileReferenceObject === null) {
                    //if ($fileReference === null) {
                    // File Reference existiert in DB nicht mehr -> wird geloescht da null
                    if ($this->debug) {
                        $this->log('found fileReference['.$fileReferenceUid.'] NOT FOUND');
                    }
                } else {
                    $fileReference = GeneralUtility::makeInstance($targetType);
                    $fileReference->setOriginalResource($fileReferenceObject);
                    if ($this->debug) {
                        $this->log('found fileReference['.$fileReferenceUid.'] uid='.$fileReference->getUid());
                    }
                }
            }
        }

        if (isset($source['uidLocal'])) {
            $fileSource = $source['uidLocal']; //$source['uidLocal']
            //$fileReferenceUid = (int)$source['uidLocal']['__identity'];
            if ($this->debug) {
                $this->log('found uidLocal by'. $fileReferenceUid);
            }
        }

        if ($this->debug) {
            $this->log('IN :'. $fileReferenceUid);
        }

        // FileReferenze von bestehendem File erzeugen
        if (isset($fileSource['langFile']) && $fileSource['langFile'] != '') {
            //$this->log('langFile='. $fileSource['langFile'] );
            $langFileId = intval($this->hashService->validateAndStripHmac($fileSource['langFile']));
            if (MathUtility::canBeInterpretedAsInteger($langFileId)
                && $langFileId>0
            ) {
                //($source['description']!='' || $source['title']!='') ) {
                // Here we have a reference ID.. so do nothing, basically ^^
                // make sure no one has tempered with it.
                //$this->log('langFile: canBeInterpretedAsInteger');


                $fileReference = $this->formUtility->createFileReferenceFromFalUid($langFileId);
            }
        } else {
            // delete fileReference
            if ($this->debug) {
                $this->log('delete???? fileReferenceUid='. $fileReferenceUid .' und remove='.$fileSource['remove']);
            }
            if ($fileReferenceUid>0 && (int)$fileSource['remove'] == 1) {
                // Delete reference
                if (is_object($fileReference)) {
                    if ($this->debug) {
                        $this->log('DELETE fileReference uid=' . $fileReference->getUid());
                    }
                    $this->fileReferenceRepository->remove($fileReference);
                }
                $fileReference = null;
            }
            // Neues File
            if (isset($fileSource['newFile']) && $fileSource['newFile'] != '') {
                $options = $this->hashService->validateAndStripHmac($fileSource['options']);
                $options = unserialize(base64_decode($options));
                $fileReference = $this->formUtility->createFileReference($fileSource['newFile'], $fileSource['origFilename'], $options, $configuration);
                if ($this->debug) {
                    $this->log('New fileReference uid=' . $fileReference->getUid());
                }
            }

            // Filereference from existing file
            if (isset($fileSource['newFileUid']) && (int)$fileSource['newFileUid'] > 0) {
                $options = $this->hashService->validateAndStripHmac($fileSource['options']);
                $options = unserialize(base64_decode($options));
                $fileReference = $this->resourceFactory->createFileReferenceObject(
                    [
                        'uid_local' => (int) $fileSource['newFileUid'], //$file->getUid(),
                        'uid_foreign' => StringUtility::getUniqueId('NEW_'),
                        'uid' => StringUtility::getUniqueId('NEW_'),
                        'crop' => null,
                    ]
                );
                
                $fileReference = $this->formUtility->createFileReferenceModelFromResource($fileReference);
                if ($this->debug) {
                    $this->log('New fileReference from file uid=' . $fileReference->getUid());
                }
            }

            // Filereference from existing file
            if (isset($fileSource['curFile']) && $fileSource['curFile'] !== '') {
                $options = $this->hashService->validateAndStripHmac($fileSource['options']);
                $options = unserialize(base64_decode($options));
                $fileUid = (int)$this->hashService->validateAndStripHmac($fileSource['curFile']);

                if($fileUid > 0) {
                    $fileReference = $this->resourceFactory->createFileReferenceObject(
                        [
                            'uid_local' => $fileUid, //$file->getUid(),
                            'uid_foreign' => StringUtility::getUniqueId('NEW_'),
                            'uid' => StringUtility::getUniqueId('NEW_'),
                            'crop' => null,
                        ]
                    );
                    $fileReference = $this->formUtility->createFileReferenceModelFromResource($fileReference);
                    if ($this->debug) {
                        $this->log('New fileReference from file uid=' . $fileReference->getUid());
                    }
                }
            }
        }

        if ($fileReference) {
            if (isset($source['title'])) {
                $fileReference->setTitle($source['title']);
                if ($this->debug) {
                    $this->log('fileReference set title :'. $source['title']);
                }
            }
            if (isset($source['description'])) {
                $fileReference->setDescription($source['description']);
            }
            if (isset($source['sortingForeign'])) {
                $fileReference->setSortingForeign($source['sortingForeign']);
            }
            if (isset($source['_languageUid'])) {
                $fileReference->set_languageUid($source['_languageUid']);
            }

            if ($this->debug) {
                $this->log('return ' . $fileReference::class);
            }

            return $fileReference;
        }

        if ($this->debug) {
            $this->log('return FileReference=NULL');
        }
        return null;
    }
    /**
     * Returns the source, if it is an array, otherwise an empty array.
     *
     * @param  mixed $source
     * @return array
     * @api
     */
    public function getSourceChildPropertiesToBeConverted($source): array
    {
        //$this->log('--> FileReferenceConverter');
        return [];
    }
}
