<?php
/* Usar apenas para validar campos.
    Como usar:

    Sem mensagem personalizada
    $this->validate->execute([
    'nome_do_campo' => [
        'value' => 'Valor',
        'validates' => ['isEmpty'],
      ],
    'nome_do_campo' => [
        'value' => 'Valor',
        'validates' => ['isEmpty'],
        'condition' => condição para executar a validação, condicação tem que ser boolean
      ]
    ]);

    Com mensagem personalizada e com parametros
    $this->validate->execute([
      'nome_do_campo' => [
        'value' => 'Valor do campo',
        'validates' => [
          [
            'method' => 'isMinMaxNumber',
            'message' => 'Mensagem personalizada',
            'min' => '5',
            'max' => '100',
            'condition' => condição para executar a validação, condicação tem que ser boolean
          ]
        ],
      ]
    ]);

    Retorno
    [
      nome_do_campo => [
        'Mensagem de erro'
      ]
    ]
  */

class Ftr_validate
{
    public function __construct($registry)
    {
        $this->registry = $registry;
        $this->load     = $registry->get('load');
        $this->config   = $registry->get('config');
        $this->session  = $registry->get('session');
        $this->db       = $registry->get('db');
        $this->cache    = $registry->get('cache');
        $this->request  = $registry->get('request');

        $this->messages = [
            'isEmpty' => 'O campo não pode ser vazio',
            'isIntegerNumber' => 'O campo deve ser um número inteiro',
            'isMinMax' => 'O campo deve ter entre $min e $max caracteres',
            'isMinMaxNumber' => 'O campo deve ser entre $min e $max',
            'isEmail' => 'O campo deve ser um e-mail válido',
            'isCpf' => 'O campo deve ser um CPF válido',
            'isCnpj' => 'O campo deve ser um CNPJ válido',
            'isCep' => 'O campo deve ser um CEP válido',
            'isUf' => 'O campo deve ser uma UF válida',
            'isNaturalOrLegalPerson' => 'O campo deve ser uma pessoa física ou jurídica',
            'isEnabledOrDisabled' => 'O campo deve ser habilitado ou desabilitado',
            'isOrderState' => 'O campo deve ser um estado de pedido válido',
            'isYesOrNo' => 'O campo deve ser sim ou não',
            'isDate' => 'O campo deve ser uma data válida',
            'isDateSmallerThanToday' => 'A data deve ser menor que a de hoje',
            'isPhone' => 'O campo dever ser um telefone válido',
            'isCellPhone' => 'O campo dever ser um celular válido',
            'isAlreadyRegisteredEmail' => 'Este e-mail já está registrado!',
            'isUrl' => 'O campo deve ser uma URL',
            'isWithoutDot' => 'O campo não permite ponto',
            'isValidIE' => 'Este campo deve ser uma inscrição estadual valida!',
            'targetIsMandatory' => 'Defina uma das opções como padrão!',
            'targetIsDuplicatedObject' => 'Não pode haver configurações repetidas!',
            'targetIsDuplicatedArray' => 'Não pode haver configurações repetidas!'
        ];
    }

    public function __get($name)
    {
        return $this->registry->get($name);
    }

    public function execute($fields, bool $onlyOne = false)
    {
        $errors = [];

        foreach ($fields as $field_key => $field) {
            $value = $field['value'];
            $validates = $field['validates'];
            $hasValidateActive = array_filter($validates, function ($validate) {
                return isset($validate['condition']) ? $validate['condition'] : true;
            });

            if ((isset($field['condition']) && !$field['condition']) || !$hasValidateActive) {
                continue;
            }

            foreach ($validates as $validate_key => $validate) {

                if (isset($validate['condition']) && !$validate['condition']) {
                    continue;
                }

                $method = isset($validate['method'])
                    ? $validate['method']
                    : $validate;

                if ($method != 'isEmpty' && (trim($value)=='')) {
                    continue;
                }

                $message = isset($validate['message']) && !empty($validate['message'])
                    ? $validate['message']
                    : $this->messages[$method];

                if (gettype($validate) === 'array') {
                    unset($validate['method']);
                    unset($validate['message']);
                }

                $params = $validate ? $validate : [];

                $error = $this->$method($value, $message, $params);
                if ($error && !$onlyOne) {
                    $errors[$field_key][] = $error;
                } else if(!is_null($error) && $onlyOne){
                    /*
                     * validação feita para retornar um erro por campo para que possamos utilizar em conjuntos com as
                     * validações antigas.
                    */
                    $errors[$field_key] = $error;
                }
            }
        }

        return $errors;
    }

    public function validateGrid($rows, $list,$action){
        $error = [];
        $arr = [];

        foreach ($list as $val){
            $arr = array_merge($arr, array($val['colum'] => []));
        }

        if($action == 'notRepeat'){
            for($countRow = 0; $countRow < count($rows); $countRow++){
                for($countList = 0; $countList < count($list); $countList++){
                    if(isset($rows[$countRow][$list[$countList]['colum']])){
                        array_push($arr[$list[$countList]['colum']],$rows[$countRow][$list[$countList]['colum']] );
                    }
                }
            }
        }
        foreach ($list as $values){
            if($arr[$values['colum']]){
                $comp = array_count_values($arr[$values['colum']]);
                foreach ($arr[$values['colum']] as $key => $arrVal){
                    if($comp[$arrVal] > 1 AND $arrVal != ""){
                        array_push($error, array($key.".".$values['name'] => "O valor informado não pode se repetir para a coluna."));
                    }
                }
            }

        }

        return $error;
    }

    public function targetIsMandatory($value, $message, $params)
    {
        extract($params);

        if (is_array($compare)) {

            $result = array_filter($compare, function($v, $k) use ($field) {
                return $v[$field] == 1 ;
            }, ARRAY_FILTER_USE_BOTH);

            if (count($result) == 0) {
                return $message;
            }

        }
    }

    public function isEmpty($value, $message, $params)
    {
        if (!utf8_strlen($value)) {
            return $message;
        }
    }

    public function isWithoutDot($value, $message, $params)
    {
        if (strpos($value, '.') > 0) {
            return $message;
        }
    }

    public function isIntegerNumber($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        if (!is_numeric($value) && !is_int($value)) {
            return $message;
        }
    }

    public function isMinMax($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        extract($params);

        $count_value = strlen(utf8_decode($value));
        if ($count_value < $min || $count_value > $max) {
            $message = str_replace(
                ['$min', '$max'],
                [$min, $max],
                $message
            );
            return $message;
        }
    }

    public function isMinMaxNumber($value, $message, $params)
    {
        $value = (float)ftr_geral::removeMaskToDouble($value);

        extract($params);

        $min = (float)$min;
        $max = (float)$max;

        if ($value < $min || $value > $max) {
            $message = str_replace(
                ['$min', '$max'],
                [$min, $max],
                $message
            );
            return $message;
        }
    }

    public function isEmail($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        if (
            utf8_strlen($value) > 96
            || !preg_match('/^[^\@]+@.*\.[a-z]{2,6}$/i', $value)
            || !filter_var($value, FILTER_VALIDATE_EMAIL)
            || !preg_match('/^[a-zA-Z0-9\._-]+@/', $value)
        ) {
            return $message;
        }
    }

    public function isCpf($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $value = ftr_geral::removeMaskToInt($value);

        if (
            strlen($value) != 11
            || $value == '00000000000'
            || $value == '11111111111'
            || $value == '22222222222'
            || $value == '33333333333'
            || $value == '44444444444'
            || $value == '55555555555'
            || $value == '66666666666'
            || $value == '77777777777'
            || $value == '88888888888'
            || $value == '99999999999'
        ) {
            return $message;
        }

        for ($t = 9; $t < 11; $t++) {
            for ($d = 0, $c = 0; $c < $t; $c++) {
                $d += $value[$c] * (($t + 1) - $c);
            }

            $d = ((10 * $d) % 11) % 10;

            if ($value[$c] != $d) {
                return $message;
            }
        }
    }

    public function isCnpj($value, $message, $params)
    {
        $value = ftr_geral::removeMaskToInt($value);

        if (strlen($value) != 14 || $value == '00000000000000') {
            return $message;
        }

        for ($t = 12; $t < 14; $t++) {
            for ($d = 0, $p = $t - 7, $c = 0; $c < $t; $c++) {
                $d += $value[$c] * $p;
                $p  = ($p < 3) ? 9 : --$p;
            }

            $d = ((10 * $d) % 11) % 10;

            if ($value[$c] != $d) {
                return $message;
            }
        }
    }

    public function isCep($value, $message, $params)
    {
        $value = ftr_geral::removeMaskToInt($value);

        if (utf8_strlen($value) !== 8) {
            return $message;
        }
    }

    public function isUf($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $count_value = strlen(utf8_decode($value));
        if ($count_value != 2) {
            return $message;
        }

        $this->load->model('localisation/zone');
        $country_id = Type_PaisId::Tp_Brasil;
        $zones = $this->model_localisation_zone->getZonesByCountryId($country_id);
        $invalidUf = true;

        foreach ($zones as $zonekey => $zone) {
            $uf = $zone['code'];

            if ($uf == $value) {
                $invalidUf = false;
            }
        }

        if ($invalidUf) {
            return $message;
        }
    }

    public function isNaturalOrLegalPerson($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $invalidTypePerson = true;
        $typePeople = Type_CadastroPessoa::getEnumList();

        foreach ($typePeople as $personKey => $person) {
            if ($value == $personKey) {
                $invalidTypePerson = false;
            }
        }

        if ($invalidTypePerson) {
            return $message;
        }
    }

    public function isEnabledOrDisabled($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $invalidStatus = true;
        $status = Type_Status::getEnumList();

        foreach ($status as $statusKey => $state) {
            if ($value == $statusKey) {
                $invalidStatus = false;
            }
        }

        if ($invalidStatus) {
            return $message;
        }
    }

    public function isOrderState($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $invalidOrderState = true;

        $this->load->model('localisation/order_status');
        $orderStatus = $this->model_localisation_order_status->getOrderStatuses();

        foreach ($orderStatus as $orderStateKey => $orderState) {
            if ($value == $orderStateKey) {
                $invalidOrderState = false;
            }
        }

        if ($invalidOrderState) {
            return $message;
        }
    }

    public function isYesOrNo($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        extract($params);

        if (!isset($type)) {
            return 'Defina o tipo: Type_DsimDnao ou Type_DsDn';
        }

        $invalidYesOrNo = true;
        $yesOrNo = $type::getEnumList();

        foreach ($yesOrNo as $yesOrNoKey => $yesOrNoValue) {
            if (strval($value) == strval($yesOrNoKey)) {
                $invalidYesOrNo = false;
            }
        }

        if ($invalidYesOrNo) {
            return $message;
        }
    }

    public function isDate($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $date = explode("/", $value);

        if (
            strlen(utf8_decode($value)) &&
            (sizeof($date) != 3 || !checkdate($date[1], $date[0], $date[2]))
        ) {
            return $message;
        }
    }

    public function isDateSmallerThanToday($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $explodedDate = explode("/", $value);
        $day = $explodedDate[0];
        $month = $explodedDate[1];
        $year = $explodedDate[2];

        $date = new DateTime($year . '-' . $month . '-' . $day);
        $today = new DateTime();

        if ($date > $today) {
            return $message;
        }
    }

    public function isPhone($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $onlyNumbers = preg_replace('/([^0-9])/i', '', $value);

        if (utf8_strlen($onlyNumbers) != 10) {
            return $message;
        }
    }

    public function isCellPhone($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        $onlyNumbers = preg_replace('/([^0-9])/i', '', $value);

        if (utf8_strlen($onlyNumbers) != 10 && utf8_strlen($onlyNumbers) != 11) {
            return $message;
        }
    }

    public function isAlreadyRegisteredEmail($value, $message, $params)
    {
        $this->load->model('account/customer');

        if ($this->model_account_customer->getTotalCustomersByEmail($value)) {
            return $message;
        }
    }

    public function isUrl($value, $message, $params)
    {
        if (empty($value)) {
            return;
        }

        if (!filter_var($value, FILTER_VALIDATE_URL)) {
            return $message;
        }
    }

    public function isValidIE($value, $message, $params)
    {
        $validator = new Ie_Validate();
        $ie = preg_replace('/([^a-z0-9])/i', '', $value);
        return $validator->isValidIE($ie, $params);
    }

    public function targetIsDuplicatedObject($data, $message, $params)
    {
        if (is_array($data)) {

            $isDuplicated = array_map(function($array) use ($params) {
                $removes = array_diff_key($array, array_flip($params));
                foreach ($removes as $key => $remove) {
                    unset($array[$key]);
                }
                return $array;
            }, $data);

            if (count($isDuplicated) !== count(array_unique($isDuplicated, SORT_REGULAR))) {
                return (is_null($message)) ? $this->messages['targetIsDuplicatedObject'] : $message ;
            }

        }

        return false;
    }

    public function targetIsDuplicatedArray($data, $message, $params)
    {
        if (is_array($data)) {

            if (count($data) !== count(array_unique($data, SORT_REGULAR))) {
                return (is_null($message)) ? $this->messages['targetIsDuplicatedArray'] : $message ;
            }

        }

        return false;
    }
}
