<?php
/**
 * Created by PhpStorm.
 * User: m.dauphin
 * Date: 09/12/2021
 * Time: 11:52
 */

namespace App\Utils;
use DateTime;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;


class Functions
{

    static function getIgnoredAttributes() {
        return [
            'types',
            'agents',
            'type_agent',
            'responsable',
            'lazyPropertiesNames',
            'lazyPropertiesDefaults',
        ];
    }

    static function isValidFloat($value) {
        return  filter_var($value, FILTER_VALIDATE_FLOAT);
    }

    static function getDateTimeFromString($dateString) {
        if (DateTime::createFromFormat('Y-m-d\TH:i:sP',$dateString) !== false) return DateTime::createFromFormat('Y-m-d\TH:i:sP',$dateString);
        else {
            $explodedDate = explode(' ', $dateString);
            return (isset($explodedDate[1]))
                ? DateTime::createFromFormat('D M d Y',$explodedDate[0] . ' ' . $explodedDate[1] . ' ' . $explodedDate[2] . ' ' . $explodedDate[3])
                : '';
        }
    }

    static function formatFiltersForBdd($filters, $datasType) {
        $value = null;
        $result =['AND' => []];

        if ($filters && is_array($filters)) {
            if (!is_array($filters[0])) {$result['AND'][] =  self::getResultByFiltersType($filters, "AND", $datasType);}
            elseif (is_array($filters[0]) && $filters[1] == 'or')  {
                //on doit mettre en place un hack car ya un bug sur la premiere recherche dans searchtext qui ne fait pas un contains mais un egal
                if (count($filters) > 8) {
                    foreach ($filters as $key => $filter) {
                        if (is_array($filter) && isset($filter[1]) && $filter[1] == '=') $filters[$key][1] = 'contains';
                    }
                }
                $result['AND'][] =  self::getResultByFiltersType($filters, "OR", $datasType);
            }
            else {
                foreach($filters as $indice => $filter) {
                    if (!is_array($filter)) continue;
                    if (is_array($filter[0])) {
                        $result['AND'][] =  self::getResultByFiltersType($filter, $filter[1], $datasType, $indice);
                    } else {
                        $result['AND'][] =  self::getResultByFiltersType($filter, 'AND', $datasType, $indice);
                    }
                }
            }
            return $result;

        } else return $result;

    }

    static function clearData($data) {
        return trim($data);
    }

    private function isValidDataTypes($type, $value) {
        if ($type == 'smallint' && $value > 32767) return false;
        if ($type == 'date' && strtotime($value) === false) return false;
        return true;
    }

    private function getResultByFiltersType($filters, $type, $datasType, $indice = 0) {
        $result = [];
        $parameters  = [];

        if (!is_array($filters[0])) {
            $filters = [$filters];
        }
        foreach ($filters as $i => $filter) {
            if (!is_array($filter)) continue;
            if (is_array($filter[0])) {
                foreach ($filter as $j => $filt) {
                    if (!is_array($filt)) continue;
                    $key = $filt[0];
                    $condition = $filt[1];
                    $value = $filt[2];

                    $tmpResult = self::getResultBddWithKeyValue($key, $condition, $j, $indice, $value, $datasType, $parameters);
                    if ($tmpResult){
                        $result['filtersPlain'][] = $tmpResult['filtersPlain'];
                        $result['filtersVariables'][] = $tmpResult['filtersVariables'];
                    }
                    else continue;
                }
            } else {
                $key = $filter[0];
                $condition = $filter[1];
                $value = $filter[2];

                $tmpResult = self::getResultBddWithKeyValue($key, $condition, $i, $indice, $value, $datasType, $parameters);
                if ($tmpResult){
                    $result['filtersPlain'][] = $tmpResult['filtersPlain'];
                    $result['filtersVariables'][] = $tmpResult['filtersVariables'];
                }
                else continue;
            }

        }
        return ['filtersPlain' => implode(' '.$type.' ',$result['filtersPlain']), 'filtersVariables' => implode(' '.$type.' ',$result['filtersVariables']), 'parameters' => $parameters];
    }

    private function getResultBddWithKeyValue($key, $condition, $indice, $indice_parent, $value, $datasType, &$parameters) {
        $pos = stripos($key, '_');
        $keyBdd = substr_replace($key,'.',$pos,1);
        $keyParameter = $key.$indice.$indice_parent;
        $realCondition = '=';

        if ($condition == 'contains' || $condition == 'startswith') $realCondition = 'LIKE';
;
        if (isset($datasType[$key]) && !self::isValidDataTypes($datasType[$key], $value))  return '';
        if (isset($datasType[$key]) && $datasType[$key] == 'binary') return '';
        if (isset($datasType[$key]) && $datasType[$key] == 'boolean') {
            if ($value == 'oui') return ['filtersPlain' => " $keyBdd  = true", 'filtersVariables' => " $keyBdd  = true"];
            elseif($value == 'non') return  ['filtersPlain' => " $keyBdd = false", 'filtersVariables' => " $keyBdd = false"];
            return '';
        }

        if (isset($datasType[$key]) && $datasType[$key] == 'date') {
            $parameters[] = ['key' => $keyParameter, 'value' => strtolower($value)];
            return [
                'filtersVariables' => "$keyBdd $condition :$keyParameter",
                'filtersPlain' => "$keyBdd $condition '". strtolower($value)."'",
                ];
        }
        elseif (isset($datasType[$key]) &&  in_array($datasType[$key], ['smallint', 'integer', 'float', 'number'])) {
            if (in_array($key, ['id','e_id'])) {
                if ($key == 'id') $key = 'c.id';
                if ($key == 'e_id') $key = 'e.id';
                return [
                    'filtersVariables' => " $key $condition :$keyParameter",
                    'filtersPlain' => " $key $condition $value",
                ];
            }
            if ($condition == '=')  $realCondition = 'LIKE';
            if ($realCondition == 'LIKE' && !in_array($condition,['startswith', '='])) $value = '%'. $value .'%';
            elseif ($realCondition == 'LIKE' && ($condition == 'startswith' || $condition == '=')) $value = $value .'%';
            $parameters[] = ['key' => $keyParameter, 'value' => strtolower($value)];
            return [
                'filtersVariables' => " CAST($keyBdd AS TEXT) $realCondition :$keyParameter",
                'filtersPlain' => " CAST($keyBdd AS TEXT) $realCondition '". strtolower($value)."'",
            ];
        }
        if ($realCondition == 'LIKE' && $condition != 'startswith') $value = '%'. $value .'%';
        else if ($realCondition == 'LIKE' && $condition == 'startswith') $value = $value .'%';
        $parameters[] = ['key' => $keyParameter, 'value' => strtolower($value)];
        return [
            'filtersVariables' => "unaccent_lower($keyBdd)  $realCondition :$keyParameter",
            'filtersPlain' => " unaccent(lower($keyBdd))  $realCondition unaccent('".strtolower(str_replace("'", "''",($value)))."')",
        ];
    }


    public function getSerialisedEntities($entities, $serializer, $groups = '') {
        $encoder = new JsonEncoder();
        $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
        $metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);
        $normalizer = new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter);

        $serializer = new Serializer(array(new DateTimeNormalizer(), $normalizer), array($encoder));
        $options['ignored_attributes'] = Functions::getIgnoredAttributes();
        if($groups != ''){
            $options['groups'] = $groups;
            $options[DateTimeNormalizer::FORMAT_KEY ] = 'Y-m-d H:i:s';
        }

        $datas = $serializer->normalize($entities,null, $options);

        return $datas;
    }

    public function isSetAndNotEmpty($variable) {
        return isset($variable) && !empty($variable);
    }

    public function escapeString($string) {
        $string = self::removeAccents($string);
        $string = strtolower(str_replace(' ', '', $string));
        $string = preg_replace('/[^a-z0-9]/', '', $string);

        return  $string;

    }

    function removeAccents($string) {
        $search =  array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
        $replace = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 'P', 'ss', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'd', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'p', 'y');

        return strtr($string, array_combine($search, $replace));
    }

    function monthFrToEn($month) {
        $mois_fr_en = [
            'janvier' => 'january',
            'février' => 'february',
            'mars' => 'march',
            'avril' => 'april',
            'mai' => 'may',
            'juin' => 'june',
            'juillet' => 'july',
            'août' => 'august',
            'septembre' => 'september',
            'octobre' => 'october',
            'novembre' => 'november',
            'décembre' => 'december'
        ];
        if ($month) {
            foreach ($mois_fr_en as $mois_fr => $mois_en) {
                if (strpos($month, $mois_fr) !== false) {
                    $date_fr = str_replace($mois_fr, $mois_en, $month);
                    return $date_fr;
                }
            }
        }
        return $month;
    }

}