<?php

namespace Internetgalerie\IgDatapoolFe\Controller;

use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use Exception;
use Internetgalerie\IgDatapoolFe\Services\LangService;
use Internetgalerie\IgDatapoolFe\Utility\NeedfulThings;
use Internetgalerie\IgDatapoolFe\Domain\Repository\Repository;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use Internetgalerie\IgDatapoolFe\Property\TypeConverter\PersistentObjectConverter;
use Internetgalerie\IgDatapoolFe\Services\FormService;
use Internetgalerie\IgDatapoolFe\Utility\FormUtility;
use Internetgalerie\IgDatapoolFe\Utility\MappingUtility;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Http\PropagateResponseException;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Http\ForwardResponse;

abstract class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
    protected $debug = false;
    protected $debugLog = '/tmp/log2.txt';

    protected $searchPrefix = '@search';

    protected $uploadSizeLimit = 104857600;  // Max file upload size in bytes (default 100MB)

    /**
     * provides methods for checking access
     *
     * @var MappingUtility
     */
    protected $mappingUtility;

    /**
     * @var LangService
     */
    protected $langService;
    /**
     * The Class of the objects we are manipulating..
     *
     * @var string
     */
    public static $currentObjectClass;

    /**
     *  use this for overrideing the static $currentObjectCLass in your Controller Subclasses
     */
    protected $objectClass = null;

    /**
     * The name of the parameter
     */
    protected $objectParamName = null;

    /**
     * A static reference to ourself.
     *
     * @var \Internetgalerie\IgDatapoolFe\Controller\ActionController
     */
    public static $currentController;

    /**
     * A static refernce to our Repository.
     *
     * @var Repository
     */
    public static $currentRepository;

    /**
     * flash message constants, put here for easer access
     */
    public const NOTICE = ContextualFeedbackSeverity::NOTICE;
    public const INFO = ContextualFeedbackSeverity::INFO;
    public const OK = ContextualFeedbackSeverity::OK;
    public const WARNING = ContextualFeedbackSeverity::WARNING;
    public const ERROR = ContextualFeedbackSeverity::ERROR;

    protected $debugEmails = false;

    /**
     * @var FormService
     */
    protected FormService $formService;

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

    /**
     * @param MappingUtility $mappingUtility
     */
    public function injectMappingUtility(MappingUtility $mappingUtility): void
    {
        $this->mappingUtility = $mappingUtility;
    }

    /**
     * @param FormService $formService
     */
    public function injectFormService(FormService $formService): void
    {
        $this->formService = $formService;
    }

    /**
     * @param FormUtility $formUtility
     */
    public function injectFormUtility(FormUtility $formUtility): void
    {
        $this->formUtility = $formUtility;
    }

    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');
        $text = var_export($var, true);
        fputs($fp, 'DUMP=' .  $text ."\n");
        fclose($fp);
    }


    /**
     * insitialize stuff
     * call parent if you overwrite thsi
     */
    protected function initializeAction(): void
    {
        /**
         * Try to find the class automagically if no class defined
         */
        parent::initializeAction();
        if ($this->objectClass == null) {
            //this could be done better, maybe?
            $s = '\\' . substr(str_replace('\\Controller\\', '\\Domain\\Model\\', static::class), 0, -strlen('Controller'));
            if (!class_exists($s, true)) {
                throw new Exception('Die Klasse der zu verwaltenden Einträge wurde zu ' . $s . ' aufgelöst, jedoch nicht gefunden? Bitte $this->objectClass setzen.');
            }
            self::$currentObjectClass = $s;
        } else {
            self::$currentObjectClass = $this->objectClass;
        }
        //set some static references
        \Internetgalerie\IgDatapoolFe\Controller\ActionController::$currentController = $this;

        if (self::$currentObjectClass) {
            $repositoryName = lcfirst(end(explode("\\", (string) self::$currentObjectClass))) . 'Repository';
            if (static::$currentRepository ?? false &&  $repositoryName) {
                static::$currentRepository = $repositoryName;
            }
        }

        $this->formService->setController($this);
        //inintialize langservice
        $this->langService = LangService::getInstance();
        $this->langService->setCurrentExtension($this->request->getControllerExtensionName());

        //enableMappingForInlineFields
        $this->mappingUtility->enableMapping($this->request, $this->arguments);

        //$this->log('enable mappging for repository: ' . $repositoryName);
        //clearsession when not step
        if ($this->actionMethodName == 'listAction') {
            $this->clearSession();
        }
    }

    /*
    protected function getErrorFlashMessage($problem = '')
    {
        $str = \Internetgalerie\IgDatapoolFe\Services\LangService::ll('global.error');
        if (( bool )$GLOBALS['BE_USER']->user) {
            $str .= '<br />' . $problem . ' - Call ' . get_class($this) . '->' . $this->actionMethodName . '()';
        }
        return $str;
    }
    */

    /**
     * AJAX file handler
     *
     */
    public function ajaxUploadAction(): ResponseInterface
    {
        $this->formUtility->setSizeLimit($this->uploadSizeLimit);
        $json = json_encode($this->formUtility->handleAjaxUpload());
        $response = $this->responseFactory->createResponse()
                                     ->withHeader('Cache-Control', 'must-revalidate')
                                     ->withHeader('Content-Type', 'application/json; charset=utf-8')
                                     ->withBody($this->streamFactory->createStream($json));
        throw new PropagateResponseException($response, 200);
    }

    /**
     * TabsAsSteps
     */

    public static $currentStep = 0;
    /**
     * Initialize the step action and set the objectMapper conjfig taht it loads the object from the session.
     */
    public function initializeStepAction(): void
    {
        // store current step
        if ($this->request->hasArgument('lastStep')) {
            self::$currentStep = intval($this->request->getArgument('lastStep'));
        }
        // set the prorperty mapping config
        $config = [];
        $config[PersistentObjectConverter::CONFIGURATION_TARGET_TYPE] = \Internetgalerie\IgDatapoolFe\Controller\ActionController::$currentObjectClass;
        $config[PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED] = true;
        $config[PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED] = true;
        if ($this->arguments->hasArgument($this->objectParamName)) {
            $mappingConfig = $this->arguments[$this->objectParamName]->getPropertyMappingConfiguration();
            $tc = GeneralUtility::makeInstance(PersistentObjectConverter::class);
            $mappingConfig->setTypeConverter($tc);
            $mappingConfig->setTypeConverterOptions(PersistentObjectConverter::class, $config);
        }
    }

    /**
     * Step Action
     * This Action is called when you have a form with steps, see Edit.html and New.html
     * for instructions.
     *
     * XXX(MB): it is unsafe to pass the $stepCount as by the form. But damage is limited, i.e. the user
     * could simply destroy his form in the worst case.
     *
     * @param AbstractEntity $object
     * @param  int                                            $step
     * @param  int                                            $stepCount
     * @param  string                                         $formAction
     * @param  string                                         $dbAction
     * @return void
     */
    public function _stepAction($object, $step, $stepCount, $formAction, $dbAction): ResponseInterface
    {
        $frontendUserAuthentication = $this->request->getAttribute('frontend.user');
        $frontendUserAuthentication->setKey('ses', md5(self::$currentObjectClass), $object);
        $GLOBALS['TSFE']->storeSessionData();

        $args = $this->request->getArguments();
        $args[$this->objectParamName] = $object;

        if ($step >= $stepCount) {
            return (new ForwardResponse($dbAction))->withArguments($args);
        }
        return (new ForwardResponse('show'))->withArguments($args);
    }

    /**
     * Clear session, since we don't want values in the New-form after something was inserted
     * Automagically called by $this->initializeAction().
     */
    protected function clearSession()
    {
        $frontendUserAuthentication = $this->request->getAttribute('frontend.user');
        $frontendUserAuthentication->setKey('ses', md5(self::$currentObjectClass), null);
    }





    // Fuer FormService.php
    public function getRequest()
    {
        return $this->request;
    }

    public function getActionMethodName()
    {
        return $this->actionMethodName;
    }
    public function getObjectArguments()
    {
        if ($this->request->hasArgument($this->objectParamName)) {
            return $this->request->getArgument($this->objectParamName);
        }
    }


    /**
     * Forward und redirect, default: search mitgeben
     */
    protected function redirectWithSearch($actionName, $controllerName = null, $extensionName = null, ?array $arguments = null, $pageUid = null, $delay = 0, $statusCode = 303)
    {
        $arguments = NeedfulThings::keepAndOverrideArgs($arguments, $this->getRequest(), [$this->searchPrefix]);
        return parent::redirect($actionName, $controllerName, $extensionName, $arguments, $pageUid, $delay, $statusCode);
    }

    public function forwardWithSearch($actionName, $controllerName = null, $extensionName = null, ?array $arguments = null)
    {
        $arguments = NeedfulThings::keepAndOverrideArgs($arguments, $this->getRequest());
        return parent::forward($actionName, $controllerName, $extensionName, $arguments);
    }



    /****************************************************************************
                               OLD STUFF
     *****************************************************************************/
    /**
     * overwrite flash message to enable translation
     */
    public function addFlashMessageTranslate($messageBody, $messageTitle = '', $severity = ContextualFeedbackSeverity::OK, $storeInSession = true)
    {
        $translated = $this->langService->translate($messageBody);
        if ($translated) {
            $messageBody = $translated;
        }
        $translated = $this->langService->translate($messageTitle);

        if ($translated && $translated!==null) {
            $messageTitle = $translated;
        }
        if ($messageTitle===0) {
            $messageTitle='';
        }

        return parent::addFlashMessage($messageBody, $messageTitle, $severity, $storeInSession);
    }





    /**
     * language service
     * call insice Initialize--- action!
     */
    protected function setLabel($oldLabel, $newLabel, $specialContext = 'main')
    {
        $this->langService->setLabel($oldLabel, $newLabel, $specialContext);
    }

    /**
     * Accesss Denied action
     * this is called when an access check fails.
     */
    /*
    public function accessDeniedAction()
    {
        $referringRequest = $this->request->getReferringRequest();
        if ($referringRequest !== null) {
            $originalRequest = clone $this->request;
            $this->request->setOriginalRequest($originalRequest);
            $this->request->setOriginalRequestMappingResults($this->arguments->getValidationResults());
            $this->forward($referringRequest->getControllerActionName(), $referringRequest->getControllerName(), $referringRequest->getControllerExtensionName(), $referringRequest->getArguments());
        }
        $this->addFlashMessage($this->getErrorFlashMessage('Access Denied'), '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
        $this->redirect('');
        return '';
    }
    */

}


