<?php

namespace Internetgalerie\IgDatapoolFe\Utility;

use Internetgalerie\IgDatapoolFe\Controller\ActionController;
use Internetgalerie\IgDatapoolFe\ViewHelpers\FormViewHelper;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Reflection\ReflectionService;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use Internetgalerie\IgDatapoolFe\Services\LangService;
use TYPO3\CMS\Extbase\Mvc\Request;
use TYPO3\CMS\Core\Utility\ArrayUtility;

class NeedfulThings
{
    /**
     * Validation annotation that trigger the askerisk flag inidcating that it is required
     */
    public static $validatorsForRequiredFlag = ['NotEmpty', 'Internetgalerie.IgDatapoolFe:NotEmpty'];
    /**
     * Reflection service singleton
     *
     * @var TYPO3\CMS\\Extbase\Reflection\ReflectionService
     */
    public static $reflectionService = null;

    /**
     * Automagically add the reuired flag if property has an accroding validator
     *
     * @param  string property
     * @return bool
     */
    public static function isRequiredByAnnotation($property)
    {
        ;
        if (!($class = ActionController::$currentObjectClass) || FormViewHelper::$curForm->isSearchForm()) {
            return false;
        }
        if (self::$reflectionService == null) {
            self::$reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
        }
        $methodTagsValues = self::$reflectionService->getPropertyTagsValues($class, $property);
        return is_array($methodTagsValues['validate']) && count(array_intersect(self::$validatorsForRequiredFlag, GeneralUtility::trimExplode(',', $methodTagsValues['validate'][0]))) > 0;
    }

    /**
     * Automagically find date fields
     * this could be slow...
     *
     * @param string $class
     */
    public static function getDateFields($class)
    {
        if (self::$reflectionService == null) {
            self::$reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
        }

        $properties = self::$reflectionService->getClassPropertyNames($class);
        $candidates = [];
        foreach ($properties as $p) {
            $tagStuff = self::$reflectionService->getPropertyTagValues($class, $p, 'var');
            if ($tagStuff[0] == '\DateTime') {
                $candidates[] = $p;
            }
        }
        return $candidates;
    }

    /**
     * Resturns the field label providing a classname and e property
     *
     * @return string;
     */
    public static function getFieldLabelByProperty($property, $formObject=null, $tablename=null, $extensionName=null)
    {
        if (isset(ActionController::$currentObjectClass)) {
            $class = ActionController::$currentObjectClass;
            $table = self::classToTable($class);
        } elseif ($formObject!==null) {
            $class=$formObject::class;
            $table = self::classToTable($class);
        } else {
            $table = $tablename;
        }

        //we can only resolve the first one in case of neste dobjects...
        $property = end(explode('.', (string) $property));

        $field = self::propertyToField($property);
        $tableAndField = $table . '.' . $field;
        if ($extensionName!==null) {
            return  LocalizationUtility::translate($tableAndField, $extensionName);
        }
        return LangService::ll($tableAndField);
    }

    /**
     * get the object class
     */
    public static function classToTable($class)
    {
        $arr = GeneralUtility::trimExplode('\\', $class, true);
        unset($arr[0]);
        return 'tx_' . strtolower(implode('_', $arr));
    }

    /**
     * get the object class
     */
    public static function propertyToField($camel)
    {
        return GeneralUtility::camelCaseToLowerCaseUnderscored($camel);
    }

    /**
     * Get the file extension
     *
     * @param $file string filename
     */
    public static function getFileExt($file)
    {
        return strtolower(substr(strrchr(basename((string) $file), '.'), 1));
    }

    /**
     * get the current FE language
     */
    public static function getCurLang(Request $request, $default = 'de')
    {
        $languageId = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id');
        if (!$languageId) {
            return $default;
        } else {
            $siteLanguage = $request->getAttribute('language', null);
            return $siteLanguage->getLocale()->getLanguageCode();
        }
    }

    /**
     * we override $myArgs with the request args that start with @, but only if they are not set in myargs
     *
     * @param  array                          $myArgs
     * @param Request $request
     * @return array
     */
    public static function keepAndOverrideArgs($myArgs, Request $request, array $prefixes = [])
    {
        if (!is_array($myArgs)) {
            $myArgs = [];
        }
        $args = $request->getArguments();
        foreach ($args as $key => $val) {
            if (!str_starts_with($key, '@')) {
                continue;
            }
            //we want to change something
            if (isset($myArgs[$key])) {
                // both are arrays, override
                if (is_array($val) && is_array($myArgs[$key])) {
                    //both arrays: set old values, then override them with new ones.
                    $temp = $val;
                    ArrayUtility::mergeRecursiveWithOverrule($temp, $myArgs[$key]);
                    $myArgs[$key] = $temp;
                }
            } else {
                $myArgs[$key] = $val;
            }
        }
        if (!empty($prefixes)) {
            foreach ($prefixes as $key) {
                if (str_starts_with((string) $key, '@')) {
                    continue;
                }
                if (!isset($myArgs[$key]) && $request->hasArgument($key)) {
                    $myArgs[$key] = $request->getArgument($key);
                }
            }
        }
        return $myArgs;
    }
}
