<?php

namespace Teknisa\Libs\Util\Login;

use Doctrine\ORM\EntityManager;
use Teknisa\Libs\Util\ActiveDirectory;
use Teknisa\Libs\Util\ConnectionCustom;
use Teknisa\Libs\Util\Repositories;
use Teknisa\Libs\Util\Utilities;
use Teknisa\Libs\Util\Environment;

class UserDataProvider implements UserData{
    const USE_ACTIVE_DIRECTORY = 'S';
    const USE_ACTIVE_DIRECTORY_EN = 'Y';
    const USE_CONTROL_SENHA = 'S';
    const USE_IP_RESTRICTION_POSITIVE = 'S';
    const USE_IP_RESTRICTION_NEGATIVE = 'N';
    const USE_IP_RESTRICTION_POSITIVE_EN = 'Y';
    const USE_IP_RESTRICTION_NEGATIVE_EN = 'N';
    const IS_ACTIVE = 'S';
    const IS_ADM_USER = 'S';

    protected $loginUrl;
    protected $loginClientSecret;

    /** @var Repositories\UserData */
    protected $repository;
    /** @var ActiveDirectory */
    protected $activeDirectory;
    /** @var Utilities */
    protected $utilities;
    /** @var EntityManager */
    protected $entityManager;
    /** @var Environment */
    protected $environment;
    /** @var ConnectionCustom */
    protected $connectionCustom;

    /**
     * @param Repositories\UserData $repository
     * @param ActiveDirectory $activeDirectory
     * @param Utilities $utilities
     * @param EntityManager $entityManager
     * @param Environment $environment
     * @param ConnectionCustom $connectionCustom
     */
    public function __construct(Repositories\UserData $repository, ActiveDirectory $activeDirectory, Utilities $utilities,
                                EntityManager $entityManager, Environment $environment, ConnectionCustom $connectionCustom) {
        $this->repository       = $repository;
        $this->activeDirectory  = $activeDirectory;
        $this->utilities        = $utilities;
        $this->environment      = $environment;
        $this->entityManager    = $entityManager;
        $this->connectionCustom = $connectionCustom;

        $config = json_decode(file_get_contents(__DIR__ . '/../../../../../config/config.json'), true);
        $this->loginUrl          = $config['loginUrl'];
        $this->loginClientSecret = $config['loginClientSecret'];
    }

    /**
     * @param $user
     * @param $password
     * @return array
     */
    public function getUserData($user, $password) {
        $userData = array( 'USER' => false );
        $operator = $this->repository->getOperatorByNmAccessOrEmail($user);
        if(!empty($operator) && $operator['ID']) {
            $this->updateEntityManagerVPD($operator);
            $userData['USER']           = $operator;
            $userData['ORGANIZATION']   = $this->repository->getOrganizacaoByNrorg($operator['ORGANIZATION_ID']);
            $accessProfile = $this->repository->getPerfAcessParcByNrorgAndNrParcNegocio($operator['ORGANIZATION_ID'], $operator['NRPARCNEGOCIO']);
            $userData['ACCESS_PROFILE'] = $accessProfile;

            $this->getPasswordParameters($operator['ID'], $operator['ORGANIZATION_ID'], $userData);
            $this->getOtherSessionValues($operator, $userData, $accessProfile);
            $this->getIpRestriction($operator['ORGANIZATION_ID'], $userData);

            if($password) {
                $this->validateAD($userData['PASSWORD_PARAMETERS'], $user, $password, $operator['ORGANIZATION_ID']);
            }
        }

        return $userData;
    }

    /**
     * @param $cdOperator
     * @param $nrOrg
     * @param $userData
     */
    public function getPasswordParameters($cdOperator, $nrOrg, &$userData) {
        $passwordParams = $this->repository->getParamSenhaByNrorg($nrOrg);
        $lastPassUp = $this->repository->getLastPasswordUpdateByCdOperador($cdOperator);
        $useControlSenha = !empty($passwordParams) && $passwordParams['IDUTCTRLSEN'] == self::USE_CONTROL_SENHA ? 'Y' : 'N';
        $useAD = !empty($passwordParams) && $passwordParams['IDUTILIZAAD'] == self::USE_ACTIVE_DIRECTORY ? 'Y' : 'N';

        $userData['PASSWORD_PARAMETERS']['USES_ACTIVE_DIRECTORY']     = $useAD;
        $userData['PASSWORD_PARAMETERS']['PASSWORD_EXPIRATION_DAYS']  = !empty($passwordParams) ? $passwordParams['NRDIASEXPSEN'] : null;
        $userData['PASSWORD_PARAMETERS']['ADM_USER_ACTIVE_DIRECTORY'] = !empty($passwordParams) ? $passwordParams['NMUSUARIOADMAD'] : null;
        $userData['PASSWORD_PARAMETERS']['IDENTIFICATION']            = !empty($lastPassUp) ? $lastPassUp['IDATUCTRLSENHA'] : null;
        $userData['PASSWORD_PARAMETERS']['UPDATE_DATE']               = !empty($lastPassUp) ? $lastPassUp['DTALTSENHA'] : null;
        $userData['PASSWORD_PARAMETERS']['USES_PASSWORD_CONTROL']     = $useControlSenha;
    }

    /**
     * @param $operator
     * @param $userData
     * @param $accessProfile
     */
    protected function getOtherSessionValues($operator, &$userData, $accessProfile) {
        $generalParams = $this->repository->getParamGeralByNrorg($operator['ORGANIZATION_ID']);
        $filial = $this->repository->getFilialByCdfilialAndNrorg($operator['CDFILIALSELECIONADA'], $operator['ORGANIZATION_ID']);
        $admUser = $this->verifyAdministratorUser($accessProfile, $generalParams);

        $userData['OTHER_SESSION_VALUES']['CDPICTPROD']        = isset($generalParams['CDPICTPROD']) ? $generalParams['CDPICTPROD'] : null;
        $userData['OTHER_SESSION_VALUES']['CDPICTPRAT']        = isset($generalParams['CDPICTPRAT']) ? $generalParams['CDPICTPRAT'] : null;
        $userData['OTHER_SESSION_VALUES']['IDUTCTRLACESWEB']   = isset($generalParams['IDUTCTRLACESWEB']) ? $generalParams['IDUTCTRLACESWEB'] : 'N';
        $userData['OTHER_SESSION_VALUES']['IDIDIOMA']          = $operator['IDIDIOMA'];
        $userData['OTHER_SESSION_VALUES']['NRORGTRAB']         = $operator['NRORGTRAB'];
        $userData['OTHER_SESSION_VALUES']['NRESTRUTTRAB']      = $operator['NRESTRUTTRAB'];
        $userData['OTHER_SESSION_VALUES']['CDEMPRESA']         = $operator['CDEMPRESA'];
        $userData['OTHER_SESSION_VALUES']['NMACESSO']          = $operator['NMACESSO'];
        $userData['OTHER_SESSION_VALUES']['NMCOMPLOPER']       = $operator['NMCOMPLOPER'];
        $userData['OTHER_SESSION_VALUES']['NRPARCNEGOCIO']     = $operator['NRPARCNEGOCIO'];
        $userData['OTHER_SESSION_VALUES']['ACL_ADMINISTRATOR'] = $admUser;


        if(isset($filial['CDFILIAL'])) {
            $userData['OTHER_SESSION_VALUES']['CDFILIAL']  = $filial['CDFILIAL'];
            $userData['OTHER_SESSION_VALUES']['NMFILIAL']  = $filial['NMFILIAL'];
        }
    }

    /**
     * @param $nrOrg
     * @param $userData
     */
    protected function getIpRestriction($nrOrg, &$userData) {
        $useIpRestriction = $this->repository->getUseIpRestrictionByNrorgAndIdativo($nrOrg, self::IS_ACTIVE);
        if(!empty($useIpRestriction) && $useIpRestriction['IDUTIPRESTRICTION'] == self::USE_IP_RESTRICTION_POSITIVE) {
            $restrictedIps = $this->repository->getIpRestrictionByNrorgAndIdativo($nrOrg, self::IS_ACTIVE);
            $ipsV4 = $ipsV6 = array();
            foreach($restrictedIps as $ip) {
                if(!empty($ip['IPV4'])) {
                    $ipsV4[] = $ip['IPV4'];
                }
                if(!empty($ip['IPV6'])) {
                    $ipsV6[] = $ip['IPV6'];
                }
            }
            $userData['IP_RESTRICTION']['IPV4'] = $ipsV4;
            $userData['IP_RESTRICTION']['IPV6'] = $ipsV6;
            $userData['IP_RESTRICTION']['USES_IP_RESTRICTION'] = self::USE_IP_RESTRICTION_POSITIVE_EN;
        } else {
            $userData['IP_RESTRICTION']['USES_IP_RESTRICTION'] = self::USE_IP_RESTRICTION_NEGATIVE_EN;
        }
    }
 
    /**
     * @param $email
     * @param $password
     * @param $identification
     * @throws \Exception
     */
    public function updatePassword($email, $password, $identification) {
        $connection = $this->entityManager->getConnection();
        $connection->beginTransaction();
        try {
            $operator = $this->repository->getOperatorByNmAccessOrEmail($email);
            $this->updateEntityManagerVPD($operator);
            $passwordParams = $this->repository->getParamSenhaByNrorg($operator['ORGANIZATION_ID']);
            $webPassword = $this->utilities->encrypt($password);
            $delphiPassword = substr($this->utilities->getDelphiPasswordEncrypted($password), 0, 20);
            $this->repository->updateOperatorPassword($operator['ID'], $operator['ORGANIZATION_ID'], $webPassword, $delphiPassword);
            $this->repository->insertControlSenha($operator['ID'], $operator['ORGANIZATION_ID'], $delphiPassword, $webPassword, $identification);

            if(isset($passwordParams['IDUTILIZAAD']) && $passwordParams['IDUTILIZAAD'] == self::USE_ACTIVE_DIRECTORY) {
                $this->activeDirectory->updatePassword($operator['NMACESSO'], $password, $operator['ORGANIZATION_ID']);
            }
            $connection->commit();
        } catch (\Exception $e) {
            $connection->rollBack();
            throw $e;
        }
    }

    /**
     * @param $passwordParams
     * @param $user
     * @param $password
     * @param $nrOrg
     * @return bool
     */
    public function validateAD($passwordParams, $user, $password, $nrOrg) {
        if(!empty($passwordParams) && $passwordParams['USES_ACTIVE_DIRECTORY'] == self::USE_ACTIVE_DIRECTORY_EN) {
            $this->activeDirectory->login($user, $password, $nrOrg);
            return true;
        }
        return false;
    }

    public function validateUser($user, $password) {
        $operator = $this->repository->getOperatorByCdoperador($user);
        $this->updateEntityManagerVPD($operator);
        $this->getPasswordParameters($operator['CDOPERADOR'], $operator['NRORG'], $passwordParams);
        $passwordParams = $passwordParams['PASSWORD_PARAMETERS'];

        if(!$this->validateAD($passwordParams, $operator['NMACESSO'], $password, $operator['NRORG'])) {
            return $this->validateUserInLogin($operator, $password, 'Yes');
        }

        $this->environment->setSessionExpired(false);
        return array(true);
    }

    public function validateUserInLogin($user, $password, $keepConnected) {
        $dataSet = array (
            "requestType" => "FilterData",
            "filter" => array (
                array (
                    'name' => 'USER',
                    'operator' => '=',
                    'value' => $user
                ), array (
                    'name' => 'PASSWORD',
                    'operator' => '=',
                    'value' => $password
                ), array (
                    'name' => 'BHASH',
                    'operator' => '=',
                    'value' => $this->environment->getBHash()
                )
            )
        );

        $userValidation = $this->utilities->callWebService($this->environment->getLoginTokenInSession(),
            '/lm_validateUser', $dataSet, 'userValidation', $this->loginClientSecret, $this->loginUrl, $keepConnected);

        if($userValidation == Utilities::INVALID_TOKEN || $userValidation == Utilities::EXPIRED_TOKEN) {
            return array( 'TOKEN_ERROR' => $userValidation );
        }

        $this->environment->setSessionExpired(false);
        return $userValidation;
    }

    /**
     * @param $operator
     */
    protected function updateEntityManagerVPD($operator)
    {
        $newEntityManager = $this->connectionCustom->updateVpdConnection($operator['ORGANIZATION_ID']);
        if ($newEntityManager) {
            $this->entityManager = $newEntityManager;
            $this->repository->setEntityManager($this->entityManager);
        }
    }

    /**
     * @param $accessProfile
     * @param $generalParams
     * @return bool
     */
    protected function verifyAdministratorUser($accessProfile, $generalParams) {
        $admUser = false;

        if((isset($generalParams['IDUTCTRLACESWEB']) && $generalParams['IDUTCTRLACESWEB'] == 'N') ||
            empty($generalParams['IDUTCTRLACESWEB'])) {
            $admUser = true;
        } else {
            foreach ($accessProfile as $profile) {
                if ($profile['IDPERFILACESSOADM'] == self::IS_ADM_USER) {
                    $admUser = true;
                    break;
                }
            }
        }

        return $admUser;
    }
} 