<?php

namespace Internetgalerie\IgDatapoolFe\ViewHelpers\Form;

use InvalidArgumentException;
use DateTime;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Page\AssetCollector;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Core\Page\PageRenderer;

class DateViewHelper extends AbstractDatetimeViewHelper
{

    static $settings = null;

    // remove if v12 is dropped
    protected PageRenderer $pageRenderer;

    public function injectPageRenderer(PageRenderer $pageRenderer): void
    {
        $this->pageRenderer = $pageRenderer;
    }

    public function __construct(
        protected readonly AssetCollector $assetCollector,
    ) {
        parent::__construct();
    }

    public function initSettings() {
        if (static::$settings === null) {
            $all = $this->configurationManager->getConfiguration(
                ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT
            );
            //tx_igdatapoolfe.
            static::$settings = $all['plugin.']['ig_datapool_fe.']['settings.'] ?? [];
        }
        return static::$settings;
    }

    
    public function initializeArguments(): void
    {
        parent::initializeArguments();

        $this->registerArgument('plugin', 'string', 'Minimum Datum', false);

        // default (browser)
        //$this->overrideArgument('class', 'string', 'class', false, 'dp-date dp-input-date');
        $this->registerArgument('min', 'string', 'Minimum Datum', false);
        $this->registerArgument('max', 'string', 'Maximum Datum', false);

        // pickadate
        $this->registerArgument('minDate', 'string', 'Minimum Datum', false);
        $this->registerArgument('maxDate', 'string', 'Maximum Datum', false);
        $this->registerArgument('dateFormat', 'string', 'Format for output', false, 'dd.mm.yyyy');
        $this->registerArgument('formatSubmit', 'string', 'Format Submit', false, 'yyyy-mm-dd');
        $this->registerArgument('typeConverterDateFormat', 'string', 'date format for DateTimeConverter (field dateFormat)', false);
        $this->registerArgument('hiddenName', 'bool', 'hiddenName', false, true);
        $this->registerArgument('selectYears', 'int', 'Jahrespulldown darstellen', false, false);
        $this->registerArgument('selectMonths', 'bool', 'Monatspulldown darstellen', false, false);
        $this->registerArgument('datepickerOptions', 'string', 'Format', false, '');
        //$this->registerArgument('language', 'string', 'Sprache für JS translations File', false);// geht nur letzte auf Seite
        $this->registerArgument('placeholder', 'string', 'Label', false, 'dd.mm.yyyy');
        $this->registerArgument('submitOnChange', 'boolean', '', false);
        $this->registerArgument('showToday', 'bool', 'Show today button', false, true);
        $this->registerArgument('showClear', 'bool', 'Show clear button', false, true);
        $this->registerArgument('showClose', 'bool', 'Show close button', false, true);
        /*
          $settings = $this->initSettings();
          if ($settings['pickadate.']['enable'] ?? false) {
          $this->overrideArgument('class', 'string', 'Label', false, 'dp-date dp-pickadate');
          } else {
          $this->overrideArgument('type', 'string', 'The field type, e.g. "text", "email", "url" etc.', false, 'date');
          }
        */
    }

    public function render(): string
    {
        $settings = $this->initSettings();
        //$pickadateEnable = $settings['pickadate.']['enable'] ?? false;
        $plugin = $this->arguments['plugin'] ?? $settings['date.']['default'] ?? '';
        if ($plugin == 'flatpickr') {
            $this->pageRenderer->loadJavaScriptModule('@dp/elements/dateFieldFlatpickr.js');
            $this->assetCollector->addJavaScript('ig-datapool-fe-flatpickr', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/flatpickr/flatpickr.min.js');
            $this->assetCollector->addStyleSheet('ig-datapool-fe-flatpickr', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/flatpickr/flatpickr.min.css');

            $request = method_exists($this->renderingContext, 'getRequest') ? $this->renderingContext->getRequest() : $this->renderingContext->getAttribute(ServerRequestInterface::class);
            $siteLanguage = $request->getAttribute('language');
            $languageCode = $siteLanguage->getLocale()->getLanguageCode();
            $localeFile = 'EXT:ig_datapool_fe/Resources/Public/JavaScript/flatpickr/l10n/' . $languageCode . '.js';
            if (file_exists(GeneralUtility::getFileAbsFileName($localeFile))) {
                $this->assetCollector->addJavaScript(
                    'ig-datapool-fe-flatpickr-lang',
                    $localeFile
                );
            } else {
                $languageCode = 'en';
            }
            return $this->renderFlatpickr('dp-flatpickr', $languageCode);
        }
        if ($plugin == 'pickadate') {
            $this->assetCollector->addStyleSheet('ig-datapool-fe-pickadate-classic', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/pickadate/lib/themes/classic.css');
            $this->assetCollector->addStyleSheet('ig-datapool-fe-pickadate-classicDate', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/pickadate/lib/themes/classic.date.css');
            $this->assetCollector->addJavaScript('ig-datapool-fe-pickadate-pickerCore', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/pickadate/lib/picker.js');
            $this->assetCollector->addJavaScript('ig-datapool-fe-pickadate-pickerDate', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/pickadate/lib/picker.date.js');
            $this->assetCollector->addJavaScript('ig-datapool-fe-pickadate-pickerTime', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/pickadate/lib/picker.time.js');
            $this->assetCollector->addJavaScript('ig-datapool-fe-pickadate-pickerLang', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/pickadate/lib/translations/de_DE.js');
            $this->pageRenderer->loadJavaScriptModule('@dp/elements/dateFieldPickadate.js');
            return $this->renderPickadate('dp-pickadate');
        }
        if (!$this->hasArgument('class')) {
            $this->arguments['class'] = 'dp-date dp-input-date';
            $this->tag->addAttribute('class', $this->arguments['class']);
        }
        if ($this->arguments['min'] ?? null) {
            $this->tag->addAttribute('min', $this->arguments['min']);
        }
        if ($this->arguments['max'] ?? null) {
            $this->tag->addAttribute('max', $this->arguments['max']);
        }
        $this->arguments['type'] = 'date';
        return parent::render();
    }

    public function renderPickadate(string $class): string
    {

        $options = [];
        $options['format']= strtolower((string) $this->arguments['dateFormat']);
        $options['formatSubmit'] =  $this->arguments['formatSubmit'];
        $options['hiddenName'] = ($this->arguments['hiddenName'] ? true : false);

        if (!$this->hasArgument('class')) {
            $this->arguments['class'] = 'dp-date ' . $class;
            $this->tag->addAttribute('class', $this->arguments['class']);
        }

        if ($this->arguments['selectYears']) {
            if ((int)$this->arguments['selectYears'] >1) {
                $options['selectYears'] =(int)$this->arguments['selectYears'];
            } else {
                $options['selectYears'] = $this->arguments['selectYears'] ? true : false;
            }
        }
        if ($this->arguments['selectMonths']) {
            $options['selectMonths'] = true;
        }
        if ($this->arguments['minDate']) {
            $date = explode('-', (string) $this->arguments['minDate']);
            if (count($date) == 3) {
                $options['min'] = [ intval($date[0]) , intval($date[1]-1) , intval($date[2]) ];
            } else {
                throw new InvalidArgumentException('format error of parameter minDate value is "' .$this->arguments['minDate'] . '" should be "YYYY-mm-dd"', 1696930920);
            }
        }
        if ($this->arguments['maxDate']) {
            $date = explode('-', (string) $this->arguments['maxDate']);
            if (count($date) == 3) {
                $options['max'] = [ intval($date[0]) , intval($date[1]-1) , intval($date[2]) ];
            } else {
                throw new InvalidArgumentException('format error of parameter maxDate value is "' .$this->arguments['maxDate'] . '" should be "YYYY-mm-dd"', 1696930921);
            }
        }
        $submitOnChange = $this->arguments['submitOnChange'] ?? '';
        $showToday = $this->arguments['showToday'];
        $showClear = $this->arguments['showClear'];
        $showClose = $this->arguments['showClose'];
        //	"formatSubmit" : "dd.mm.yyyy",
        if (!$showToday) {
            $options['today'] = null;
        }
        if (!$showClear) {
            $options['clear'] = null;
        }
        if (!$showClose) {
            $options['close'] = null;
        }

        if ($this->arguments['datepickerOptions']) {
            if (is_array($this->arguments['datepickerOptions'])) {
                $options = array_merge($options, $this->arguments['datepickerOptions']);
            } else {
                // support older string format
                $datepickerOptions = json_decode('{' . str_replace('\'', '"', $this->arguments['datepickerOptions']) .'}', true);
                $options = array_merge($options, $datepickerOptions);
            }
        }

        //$options = '{' .  $datepickerOptions;
        //$options = rtrim(rtrim($options), ',') . '}';

        $value = $this->getValueAttribute();

        if ($this->isObjectAccessorMode()) {
            $value = $this->getPropertyValue();
        }

        //$value = $this->convertToPlainValue($value);
        // is property Value
        if ($value instanceof DateTime) {
            $typeConverterDateFormat = $this->getTypeConverterFormatSubmit();
            $value = $value->format($typeConverterDateFormat);
            //$value = $value->format('Y-m-d');
        }

        $this->tag->addAttribute('data-dateoptions', json_encode($options));
        $this->tag->addAttribute('data-value', $value);
        if ($submitOnChange) {
            $this->tag->addAttribute('data-submit', $submitOnChange);
        }
        $res = parent::render();
        $res .= $this->getInputDateFormat();
        return $res;

    }

    private function convertToFlatpickrFormat(string $format): string
    {
        $map = [
            'dd' => 'd',
            'mm' => 'm',
            'yyyy' => 'Y',
            'yy' => 'y'
        ];

        return str_replace(array_keys($map), array_values($map), strtolower($format));
    }

    public function renderFlatpickr(string $class, string $languageCode = 'en'): string
    {
        $options = [];

        $options['locale'] = $languageCode;

        if (!$this->hasArgument('class')) {
            $this->arguments['class'] = 'dp-date ' . $class;
            $this->tag->addAttribute('class', $this->arguments['class']);
        }

        // Convert format dd.mm.yyyy → d.m.Y
        $format = $this->convertToFlatpickrFormat((string)$this->arguments['dateFormat']);
        $submitFormat = $this->convertToFlatpickrFormat((string)$this->arguments['formatSubmit']);

        // display vs submit format
        if ($this->arguments['hiddenName']) {
            $options['altInput'] = true;
            $options['altFormat'] = $format;
            $options['dateFormat'] = $submitFormat;
        } else {
            $options['dateFormat'] = $format;
        }

        // year dropdown
        if ($this->arguments['selectYears']) {
            $options['yearSelectorType'] = 'dropdown';
        }

        // month dropdown
        if ($this->arguments['selectMonths']) {
            $options['monthSelectorType'] = 'dropdown';
        }

        // minDate
        if ($this->arguments['minDate']) {
            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $this->arguments['minDate'])) {
                $options['minDate'] = $this->arguments['minDate'];
            } else {
                throw new InvalidArgumentException(
                    'format error of parameter minDate value is "' . $this->arguments['minDate'] . '" should be "YYYY-mm-dd"',
                    1696930920
                );
            }
        }

        // maxDate
        if ($this->arguments['maxDate']) {
            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $this->arguments['maxDate'])) {
                $options['maxDate'] = $this->arguments['maxDate'];
            } else {
                throw new InvalidArgumentException(
                    'format error of parameter maxDate value is "' . $this->arguments['maxDate'] . '" should be "YYYY-mm-dd"',
                    1696930921
                );
            }
        }

        // additional options
        if ($this->arguments['datepickerOptions']) {
            if (is_array($this->arguments['datepickerOptions'])) {
                $options = array_merge($options, $this->arguments['datepickerOptions']);
            } else {
                $datepickerOptions = json_decode(
                    '{' . str_replace('\'', '"', $this->arguments['datepickerOptions']) . '}',
                    true
                );
                $options = array_merge($options, $datepickerOptions);
            }
        }

        $value = $this->getValueAttribute();

        if ($this->isObjectAccessorMode()) {
            $value = $this->getPropertyValue();
        }

        if ($value instanceof DateTime) {
            $typeConverterDateFormat = $this->getTypeConverterFormatSubmit();
            $value = $value->format($typeConverterDateFormat);
        }

        $this->tag->addAttribute('data-dateoptions', json_encode($options));
        $this->tag->addAttribute('data-value', $value);

        if ($this->arguments['submitOnChange']) {
            $this->tag->addAttribute('data-submit', true);
        }

        $res = parent::render();
        $res .= $this->getInputDateFormat();

        return $res;
    }   
}
