<?php

namespace Teknisa\Libs\Service;

use Teknisa\Libs\Exception\CustomException;
use Teknisa\Libs\Util\ActiveDirectory;
use Teknisa\Libs\Util\InstanceProvider;
use Teknisa\Libs\Util\Messages;
use Teknisa\Libs\Util\Utilities;
use Teknisa\Libs\Util\Environment;
use Teknisa\Libs\Util\Repositories;
use Zeedhi\Framework\Session\Session;

class Login {
    const DATE_TYPE_DAY = 'D';
    const RECURRENCE_DAYS = 7;
    CONST TMP_PATH = '/tmp';

    /** @var Session $sessionManager */
    protected $sessionManager;
    protected $loginUrl;
    protected $loginClientSecret;

    /** @var Utilities */
    private $utilities;
    /** @var Environment */
    private $environment;
    /** @var ActiveDirectory */
    private $activeDirectory;
    /** @var Repositories\UserData */
    private $userDataRepository;

    private $libClientId;
    private $libClientSecret;

    /**
     * @param $sessionManager
     * @param Utilities $utilities
     * @param Environment $environment
     * @param ActiveDirectory $activeDirectory
     * @param Repositories\UserData $userDataRepository
     */
    public function __construct($sessionManager, Utilities $utilities, Environment $environment, ActiveDirectory $activeDirectory,
                                Repositories\UserData $userDataRepository){
        $this->sessionManager  = $sessionManager;
        $this->utilities       = $utilities;
        $this->environment     = $environment;
        $this->activeDirectory = $activeDirectory;

        $config = Utilities::getLoginConfig();
        $this->loginUrl          = $config['loginUrl'];
        $this->loginClientSecret = $config['loginClientSecret'];
        $this->userDataRepository = $userDataRepository;

        $integration = Utilities::getLoginIntegration();
        $this->libClientId     = $integration['clientId'];
        $this->libClientSecret = $integration['clientSecret'];
    }

    /**
     * @return null|string
     */
    public function getBHash() {
        return $this->sessionManager->get('CURRENT_DBNAME');
    }

    /**
     * @param $userData
     * @param $loginUserInfo
     * @param $isLogged
     * @param $modulesVersionError
     * @param $loginToken
     * @param $loginLang
     * @param $loginSep
     * @throws \Exception
     * @return array
     */
    public function restoreSession($userData, $loginUserInfo, $isLogged, $modulesVersionError, $loginToken, 
        $loginLang = null, $loginSep = null, $notices = [], $timeOutNotices = []) {
        if(!empty($userData)) {
            if(isset($loginUserInfo['CURRENT_SECONDS'])) {
                if (microtime(true) - $loginUserInfo['CURRENT_SECONDS'] > 60) {
                    return array();
                } else {
                    unset($loginUserInfo['CURRENT_SECONDS']);
                }
            }
            if(empty($userData['USER'])) {
                return array();
            }
            if($loginLang) {
                $auxLang   = explode('_', $loginLang);
                $loginLang = $auxLang[0] . '_' . strtoupper($auxLang[1]);
            }
            $loginUser          = Utilities::zeedhiEncrypt(json_encode($loginUserInfo));
            $user               = $userData['USER'];
            $organization       = $userData['ORGANIZATION'];
            $accessProfile      = Utilities::getArrayFromAssociativeArray($userData['ACCESS_PROFILE']);
            $otherSessionValues = isset($userData['OTHER_SESSION_VALUES']) ? $userData['OTHER_SESSION_VALUES'] : array();
            
            $supportOperator   = isset($loginUserInfo['IS_SUPPORT_OPERATOR']) ? $loginUserInfo['IS_SUPPORT_OPERATOR'] : false;
            $supportOperatorId = isset($user['OPER_SUP_ID']) ? $user['OPER_SUP_ID'] : false;
            $customizationURL  = isset($loginUserInfo['CUSTOMIZATION_URL']) ? $loginUserInfo['CUSTOMIZATION_URL'] : null;
            $customizationMenus = isset($loginUserInfo['CUSTOMIZATION_MENUS']) ? $loginUserInfo['CUSTOMIZATION_MENUS'] : null;

            $entityManager = InstanceProvider::getConnectionCustom()->updateVpdConnection($user['ORGANIZATION_ID']);
            if($entityManager) {
                $this->userDataRepository->setEntityManager($entityManager);
            }

            if ($loginLang != 'pt_BR') {
                $notices = $timeOutNotices = [];
            }

            $this->initSession($user, $organization, $accessProfile, $otherSessionValues, $loginUserInfo, $loginLang, 
                $supportOperator, $supportOperatorId, $loginSep, $customizationURL, $customizationMenus, $notices, $timeOutNotices);
            $userData = $this->factorySessionData($user, $organization, $accessProfile, $otherSessionValues, $loginUserInfo,
                $modulesVersionError, $loginUser, $loginToken, $supportOperator, $supportOperatorId, $customizationURL, $customizationMenus, $notices, $timeOutNotices);

            return $userData;
        } else {
            throw new CustomException('ERR_REQUEST_USER_DATA');
        }
    }

    /**
     * @param $user
     * @param $organization
     * @param $accessProfile
     * @param $otherSessionValues
     * @param array $loginUserInfo
     * @param $modulesVersionError
     * @param $loginUser
     * @param $loginToken
     * @return array
     */
    private function factorySessionData($user, $organization, $accessProfile, $otherSessionValues, $loginUserInfo,
                                        $modulesVersionError, $loginUser, $loginToken, $supportOperator = false, 
                                        $supportOperatorId = false, $customizationURL = null, $customizationMenus = null,
                                        $notices = [], $timeOutNotices = []) {
        $this->environment->setLoginTokenInSession($loginUserInfo['TOKEN']);
        if(empty($loginToken)) {
            $loginToken = InstanceProvider::getOAuthCustom()->grantAccessToken(
                $this->libClientId,
                $this->libClientSecret,
                array('sessionId' => InstanceProvider::getSession()->getId()),
                $loginUserInfo['TOKEN']
            );
        }
        $loginUserNext = $loginUserInfo;
        unset($loginUserNext['VISIBLE_ELEMENTS']);
        unset($loginUserNext['EXPIRED_ELEMENTS']);

        $sessionData = array(
            "USER_ID"         => $user['ID'],
            "USER_NAME"       => $user['NAME'],
            "EMAIL"           => $user['EMAIL'],
            "ORGANIZATION_ID" => $user['ORGANIZATION_ID'],

            "TRADING_NAME" => $organization['TRADING_NAME'],
            "COMPANY_NAME" => $organization['COMPANY_NAME'],

            "REDIRECT_URL"     => $loginUserInfo['REDIRECT_URL'],
            "VISIBLE_ELEMENTS" => $loginUserInfo['VISIBLE_ELEMENTS'],
            "EXPIRED_ELEMENTS" => isset($loginUserInfo['EXPIRED_ELEMENTS']) ? $loginUserInfo['EXPIRED_ELEMENTS'] : [],
            
            "IDUTLPERFILFILIAL"   => $this->environment->getIdUtlPerfilFilial(),
            "CDPERFILSELECIONADO" => $this->environment->getNrPerfil(),

            "LOGGED"                => true,
            "SESSION_EXPIRED"       => $this->environment->getSessionExpired(),
            "IS_PENDENT_MIGRATION"  => $this->checkPendentMigrations($user['ORGANIZATION_ID'], $loginUserInfo['REPOSITORIES_INFO']),
            "MODULES_VERSION_ERROR" => $modulesVersionError,
            "ACCESS_PROFILE"        => $accessProfile,
            "IS_TEKNISA_USER"       => isset($loginUserInfo['IS_TEKNISA_USER']) ? $loginUserInfo['IS_TEKNISA_USER'] : false,

            "LOGIN_TOKEN"         => $loginToken,
            "LOGIN_USER"          => $loginUser,
            "LOGIN_USER_NEXT"     => Utilities::zeedhiEncrypt(json_encode($loginUserNext)),
            "IS_SUPPORT_OPERATOR" => $supportOperator,
            "SUPPORT_OPERATOR_ID" => $supportOperatorId,              
            "PHP_VERSION_ID"      => PHP_VERSION_ID,
            "CUSTOMIZATION_URL"   => $customizationURL,
            "CUSTOMIZATION_MENUS" => $customizationMenus,
            "NOTICES"             => $notices,
            "TIMEOUTNOTICES"      => $timeOutNotices,
        );
        
        if(isset($loginUserInfo['FILE_SERVER_API_KEY'])) {
            $sessionData["FILE_SERVER_API_KEY"] = $loginUserInfo["FILE_SERVER_API_KEY"];
        }
        
        if(isset($user['NRORGOPER'])) {
            $sessionData["NRORGOPER"] = $user["NRORGOPER"];
        }
        
        foreach($otherSessionValues as $key => $otherValue) {
            $sessionData[$key] = $otherValue;
        }

        return $sessionData;
    }

    /**
     * @param $nrOrg
     * @param $repositoriesInfo
     * @return bool
     */
    private function checkPendentMigrations($nrOrg, $repositoriesInfo) {
        $isPendentMigration = false;

		try {
			$migrationInfo = InstanceProvider::getMigrationService()->getPendentMigrations($nrOrg, $repositoriesInfo);
		} catch (\Exception $e) {
			$migrationInfo = array();
		}

		$migFileContents = null;
		$migFilePath = Utilities::getProductBasePath() . DIRECTORY_SEPARATOR . 'migFile.tek';
		if(is_file($migFilePath)) {
			$contents = @file_get_contents($migFilePath);
			if($contents) {
				$migFileContents = json_decode($contents, true);
			}
		}

		if(!empty($migrationInfo) && !isset($migrationInfo['ERROR']) && !empty($migFileContents)) {
			foreach ($migrationInfo as $migration) {
				foreach ($migFileContents as $migFile) {
					$migFileNumber = @Utilities::zeedhiDecrypt($migFile['fileNumber']);
					if(!empty($migFileNumber)) {
						$migFileDesc = substr($migFile['repository'], -50);
						$migConfigDesc = substr($migration['REPOSITORY_URL'], -50);
						if ($migFileDesc == $migConfigDesc && intval($migration['MIG_LAST_FILE_NUMBER']) < intval($migFileNumber)) {
							$isPendentMigration = true;
							break;
						}
					}
				}
			}
		}

        return $isPendentMigration;
    }

    /**
     * @param $project
     * @param $eraseHash
     * @param $hash
     */
    public function logout($project, $eraseHash, $hash) {
        $this->sessionManager->start();
        $token = $this->environment->getLoginTokenInSession();
        $user  = $this->environment->getCurrentUserId();
        $organizationId = $this->environment->getCurrentOrganizationId();

        if($eraseHash != 'Y' && $hash) {
            try {
                if(Utilities::getConcurrentAccessSaveInMongoParameter()) {
                    InstanceProvider::getMongoCache()->deleteAccess($user, $project, $hash, $organizationId);
                } else {
                    $this->userDataRepository->deleteOperatorHash($user, $project, $hash, $organizationId);
                }
            } catch(\Exception $e) {}
        }

        InstanceProvider::getOAuthCustom()->deleteToken($token);
        $this->sessionManager->destroy();
    }

    /**
     * @param $user
     * @param $organization
     * @param $accessProfile
     * @param $otherSessionValues
     * @param $loginUserInfo
     */
    private function initSession($user, $organization, $accessProfile, $otherSessionValues, $loginUserInfo, $loginLang, $supportOperator = false, 
                                 $supportOperatorId = false, $loginSep = null, $customizationURL = null, $customizationMenus = null, 
                                 $notices = [], $timeOutNotices = [])
    {
        if(!isset($loginUserInfo['CURRENT_SECONDS'])) {
            $loginUserInfo['CURRENT_SECONDS'] = microtime(true);
        }
        
        $idUtlPerfilFilial = $this->userDataRepository->getIdUtlPerfilFilial($user['ORGANIZATION_ID']);
        $idUtlPerfilFilial = empty($idUtlPerfilFilial) ? 'N' : $idUtlPerfilFilial['IDUTLPERFILFILIAL'];
        if($idUtlPerfilFilial == 'S') {
            $perfilSelecionado = $this->userDataRepository->getPerfilSelecionado($user['ORGANIZATION_ID'], $user['ID']);
            $this->sessionManager->set('CDPERFILSELECIONADO', $perfilSelecionado['CDPERFILSELECIONADO']);
        }

        $this->sessionManager->start();

        $this->sessionManager->set('USER_ID',         $user['ID']);
        $this->sessionManager->set('USER_NAME',       $user['NAME']);
        $this->sessionManager->set('EMAIL',           $user['EMAIL']);
        $this->sessionManager->set('ORGANIZATION_ID', $user['ORGANIZATION_ID']);
        $this->sessionManager->set('TRADING_NAME',    $organization['TRADING_NAME']);

        $this->sessionManager->set('CDOPERADOR',  $user['ID']);
        $this->sessionManager->set('NMOPERADOR',  $user['NAME']);
        $this->sessionManager->set('DSEMAILOPER', $user['EMAIL']);
        $this->sessionManager->set('NRORG',       $user['ORGANIZATION_ID']);
        $this->sessionManager->set('NMORG',       $organization['TRADING_NAME']);
        
        $this->sessionManager->set('IDUTLPERFILFILIAL', $idUtlPerfilFilial);

        if(isset($loginUserInfo['FILE_SERVER_API_KEY'])) {
            $this->sessionManager->set('FILE_SERVER_API_KEY', $loginUserInfo['FILE_SERVER_API_KEY']);
        }

        if(isset($user['NRORGOPER'])) {
            $this->sessionManager->set('NRORGOPER', $user['NRORGOPER']);
        }
            
        $this->sessionManager->set('ACCESS_PROFILE',   $accessProfile);
        $this->sessionManager->set('LOGIN_USER_INFO',  $loginUserInfo);
        $this->sessionManager->set('LOGIN_LANGUAGE',   $loginLang);
        $this->sessionManager->set('LOGIN_SEPARATOR',  $loginSep);

        $this->sessionManager->set('IS_SUPPORT_OPERATOR', $supportOperator);
        $this->sessionManager->set('SUPPORT_OPERATOR_ID', $supportOperatorId);
        if ($supportOperator) {
            $this->sessionManager->set('SUPPORT_OPERATOR_EXPIRATION_DATE', $user['DTLIMACESSOSUP']);
        }
        
        $this->sessionManager->set('LOGIN_CUSTOMIZATION_URL', $customizationURL);
        $this->sessionManager->set('LOGIN_CUSTOMIZATION_MENUS', $customizationMenus);
        
        if(!empty($loginUserInfo['ACCESS_HOURS'])) {
            $this->sessionManager->set('ACCESS_HOURS_INI', $loginUserInfo['ACCESS_HOURS']['HORACESSOINI']);
            $this->sessionManager->set('ACCESS_HOURS_END', $loginUserInfo['ACCESS_HOURS']['HORACESSOFIM']);
            $this->sessionManager->set('ACCESS_HOURS_DAYS', explode(',', $loginUserInfo['ACCESS_HOURS']['DIASEMANA']));
        }

        foreach($otherSessionValues as $key => $otherValue) {
            $this->sessionManager->set($key, $otherValue);
        }

        $this->sessionManager->set('NOTICES', $notices);
        $this->sessionManager->set('TIMEOUTNOTICES', $timeOutNotices);
        $this->sessionManager->set('IS_TEKNISA_USER', isset($loginUserInfo['IS_TEKNISA_USER']) ? $loginUserInfo['IS_TEKNISA_USER'] : false);
    }

    /**
     * @param $timeout
     * @return array
     */
    public function validateExpiredSession($timeout) {
        $lastRequestTime = $this->sessionManager->get('LAST_REQUEST_TIME');
        $sessionInfo = array('IS_EXPIRED' => false);

        if($lastRequestTime) {
            $date = new \DateTime();
            $actualRequestTime = $date->getTimestamp();
            $diffTime = $actualRequestTime - $lastRequestTime;

            if($diffTime >= ($timeout / 1000)) {
                $sessionInfo['IS_EXPIRED'] = true;
                $this->environment->setSessionExpired(true);
            } else {
                $sessionInfo['TIMEOUT'] = $timeout - ($diffTime * 1000);
            }
        }

        return $sessionInfo;
    }

    /**
     * @param $user
     * @param $accessProfile
     * @param $otherSessionValues
     * @param $loginUser
     * @return array
     */
    public function updateSession($user, $accessProfile, $otherSessionValues, $loginUser) {
        $loginUserInfo = json_decode(Utilities::zeedhiDecrypt($loginUser), true);

        if(!empty($user)) {
            if (isset($user['NAME'])) {
                $this->sessionManager->set('USER_NAME', $user['NAME']);
                $loginUserInfo['USER_DATA']['USER']['NAME'] = $user['NAME'];
            }
            if (isset($user['EMAIL'])) {
                $this->sessionManager->set('EMAIL', $user['EMAIL']);
                $loginUserInfo['USER_DATA']['USER']['EMAIL'] = $user['EMAIL'];
            }
        }
        if(!empty($accessProfile)) {
            $this->sessionManager->set('ACCESS_PROFILE', Utilities::getArrayFromAssociativeArray($accessProfile));
            $loginUserInfo['USER_DATA']['ACCESS_PROFILE'] = $accessProfile;
        }
        if(!empty($otherSessionValues)) {
            foreach ($otherSessionValues as $key => $otherValue) {
                $this->sessionManager->set($key, $otherValue);
                $loginUserInfo['USER_DATA']['OTHER_SESSION_VALUES'][$key] = $otherValue;
            }
        }

        return array(Utilities::zeedhiEncrypt(json_encode($loginUserInfo)));
    }

    public function saveProductsPermission($licenseInfo) {
        $oAccTekMgrRepository = InstanceProvider::getLibOAccTekMgrRepository();
        $organizationId = InstanceProvider::getSession()->get('NRORGOPER') ?: InstanceProvider::getEnvironment()->getCurrentOrganizationId();
        $userId = $licenseInfo['USER_ID'];
        $relatedOrgIds = $licenseInfo['RELATED_ORG_IDS'];
        $organizationAndBranchesIds = $licenseInfo['ORGS_AND_BRANCHES'];
        $productId = Utilities::getProjectIdParameter();

        $licences = array(
            'products'                   => $licenseInfo['PRODUCTS_PERMISSION'],
            'relatedOrgs'                => $licenseInfo['RELATED_ORGS'],
            'relatedOrgIds'              => $relatedOrgIds,
            'organizationAndBranchesIds' => $organizationAndBranchesIds
        );
        $licences   = Utilities::zeedhiEncrypt(json_encode($licences), Utilities::LOGIN_CRYPT_STRING);
        $oAccTekMgr = $oAccTekMgrRepository->getOAccTekMgr($organizationId);

        if(empty($oAccTekMgr)) {
            $oAccTekMgrRepository->insertOAccTekMgr($organizationId, $userId, self::RECURRENCE_DAYS, $licences);
        } else {
            $oAccTekMgr = $oAccTekMgr[0];
            $lastupdate = \DateTime::createFromFormat('d/m/Y', $oAccTekMgr['DTULTATU']);
            $interval   = 'P' . $oAccTekMgr['RECURRENCE_DAYS'] . self::DATE_TYPE_DAY;
            $lastupdate->add(new \DateInterval($interval));
            $actualDate = new \DateTime();

            $oAccTek = json_decode(Utilities::zeedhiDecrypt($oAccTekMgr['OACCTEK'], Utilities::LOGIN_CRYPT_STRING), true);

            $actualRelatedOrgIds = isset($oAccTek['relatedOrgIds']) ? $oAccTek['relatedOrgIds'] : array();
            $isDiffOrgIds = !empty(array_diff($relatedOrgIds, $actualRelatedOrgIds)) ||
                            !empty(array_diff($actualRelatedOrgIds, $relatedOrgIds));

            $actualOrgAndBranchesIds = isset($oAccTek['organizationAndBranchesIds']) ? $oAccTek['organizationAndBranchesIds'] : array();
            $isDiffOrgAndBranchesIds = !empty($organizationAndBranchesIds) &&
									   (!empty(Utilities::arrayRecursiveDiff($organizationAndBranchesIds, $actualOrgAndBranchesIds)) ||
                                        !empty(Utilities::arrayRecursiveDiff($actualOrgAndBranchesIds, $organizationAndBranchesIds)));

            $actualCustomUrl = null;
            $actualCustomMenus = array();
            foreach ($oAccTek['products'] as $product) {
                if ($product['productId'] == $productId) {
                    if(isset($product['customizationURL'])) {
                        $actualCustomUrl = $product['customizationURL'];
                    }
                    if(isset($product['customizationMenus'])) {
                        $actualCustomMenus = $product['customizationMenus'];
                    }
                }
            }
            $isDiffCustomization = $licenseInfo['CUSTOMIZATION_URL'] != $actualCustomUrl || 
                !empty(Utilities::arrayRecursiveDiff($actualCustomMenus, $licenseInfo['CUSTOMIZATION_MENUS']));

            if (Utilities::getDateIntervalInSeconds($lastupdate, $actualDate) > 0 || $isDiffOrgIds || $isDiffOrgAndBranchesIds || $isDiffCustomization) {
                $oAccTekMgrRepository->updateOAccTekMgr($organizationId, $userId, self::RECURRENCE_DAYS, $licences);
            }
        }
    }

    /**
     * @param $variableMeasure
     * @param $userId
     * @param $userName
     * @param $organizationId
     * @param $teknisaOrgId
     * @param $defaultOrgId
     * @return array
     * @throws \Exception
     */
    public function getVariableMeasureRegisters($licenseInfo) 
    {
        $organizationId = InstanceProvider::getSession()->get('NRORGOPER') ?: InstanceProvider::getEnvironment()->getCurrentOrganizationId();
        $userId = $licenseInfo['USER_ID'];
        $userName = $licenseInfo['USER_NAME'];
        $relatedOrgIds = $licenseInfo['RELATED_ORG_IDS'];
        $organizationAndBranchesIds = $licenseInfo['ORGS_AND_BRANCHES'];
        $variableMeasure = $licenseInfo['VARIABLE_MEASURE'];
        $primaryId = $licenseInfo['PRIMARY_ID'];
        $teknisaOrgId = $licenseInfo['TEKNISA_ORG_ID'];

        $orgsAndBranches = array();
        foreach($organizationAndBranchesIds as $branches) {
            if($branches['NRORG'] == $organizationId) {
                $orgsAndBranches[] = $branches['FILIAL'];
            }
        }
        $orgsAndBranches = json_encode($orgsAndBranches);

        $variableMeasureToUpdate = array();        
        foreach($variableMeasure as $variableMeasureRegister) {
            $product = $variableMeasureRegister['NREXTERNAL_PRODUCT_ID'];
            $count = $log = $error = null;
            $countOutput = $this->execPHPScriptVariableMeasure($variableMeasureRegister, $organizationId, false, $product, $primaryId, $orgsAndBranches);
            $countOutputDecoded = @json_decode($countOutput, true);
            if(empty($countOutputDecoded)) {
                $error = $countOutput;
            } else {
                $count = isset($countOutputDecoded[0]) && is_array($countOutputDecoded[0]) ?
                    $countOutputDecoded[0]['COUNT'] : $countOutputDecoded['COUNT'];
            }
            if(!empty($error)) {
                $variableMeasureToUpdate[] = $this->buildVariableMeasureRow($variableMeasureRegister, $count, $log, $product,
                    $userId, $userName, $teknisaOrgId, $error);
            } else if(empty($variableMeasureRegister['ACTUAL_COUNT']) || $variableMeasureRegister['ACTUAL_COUNT'] < $count) {
                $logOutput = $this->execPHPScriptVariableMeasure($variableMeasureRegister, $organizationId, true, $product, $primaryId, $orgsAndBranches);
                $logOutputDecoded = @json_decode($logOutput, true);
                if(empty($logOutputDecoded)) {
                    $error = $logOutput;
                } else {
                    $log = $logOutputDecoded;
                }
                $variableMeasureToUpdate[] = $this->buildVariableMeasureRow($variableMeasureRegister, $count, $log, $product,
                    $userId, $userName, $teknisaOrgId, $error);
            }
        }
        return $variableMeasureToUpdate;
    }

    public function getGeneralCollectionRegisters($licenseInfo) {
        $organizationId = InstanceProvider::getSession()->get('NRORGOPER') ?: InstanceProvider::getEnvironment()->getCurrentOrganizationId();
        $userId = $licenseInfo['USER_ID'];
        $userName = $licenseInfo['USER_NAME'];
        $relatedOrgIds = $licenseInfo['RELATED_ORG_IDS'];
        $organizationAndBranchesIds = $licenseInfo['ORGS_AND_BRANCHES'];
        $generalCollection = $licenseInfo['GENERAL_COLLECTION'];
        $primaryId = $licenseInfo['PRIMARY_ID'];
        $teknisaOrgId = $licenseInfo['TEKNISA_ORG_ID'];

        $variableMeasureToUpdate = array();
        foreach($generalCollection as $generalCollectionRegister) {
            $product = $generalCollectionRegister['NREXTERNAL_PRODUCT_ID'];
            $log = $error = null;
            $logOutput = $this->execPHPScriptGeneralCollection($generalCollectionRegister, $organizationId);
            $logOutputDecoded = @json_decode($logOutput, true);
            if(empty($logOutputDecoded)) {
                $error = $logOutput;
            } else {
                $log = $logOutputDecoded;
            }
            $variableMeasureToUpdate[] = $this->buildGeneralCollectionRow($generalCollectionRegister, $log, $product,
                $userId, $userName, $teknisaOrgId, $error);
        }

        return $variableMeasureToUpdate;
    }

    public function saveVariableMeasure($variableMeasure, $generalCollection, $licenseInfo) {
        $params = array(
            "requestType" => "DataSet",
            "dataset"     => array($variableMeasure, $generalCollection)
        );
        return Utilities::callWebService($licenseInfo['LICENSE_TOKEN'], '/variableMeasure/save', $params, 
            'variableMeasureResult', $licenseInfo['LICENSE_SECRET'], $licenseInfo['LICENSE_URL']);
    }

    /**
     * @param array $variableMeasureRegister
     * @param $count
     * @param $log
     * @param $product
     * @param $userId
     * @param $userName
     * @param $organizationId
     * @param $error
     * @return array
     */
    protected function buildVariableMeasureRow($variableMeasureRegister, $count, $log, $product, $userId, $userName, $organizationId, $error) {
        return array(
            'COUNT' => $count,
            'ERROR' => $error,
            'LOG'   => $log,

            'PRODUCT_ID'   	  => $product,
            'OPERATOR_CODE'   => $userId,
            'OPERATOR_NAME'   => $userName,
            'ORGANIZATION_ID' => $organizationId,

            'ID'              => $variableMeasureRegister['ID'],
            'PRODUCT_NAME' 	  => $variableMeasureRegister['NMPRODUTO'],
            'MEASURE_CODE' 	  => $variableMeasureRegister['CDTPMEDIDASERV'],
            'MEASURE_NAME' 	  => $variableMeasureRegister['DSTPMEDIDASERV'],
            'INIT_COMPETENCE' => $variableMeasureRegister['DTINICOMPET'],
            'END_COMPETENCE'  => $variableMeasureRegister['DTFINCOMPET'],

            'CONTRACT_REFERENCE' => $variableMeasureRegister['DSREFERENCIAORCA'],
            'CONTRACT_ID'        => $variableMeasureRegister['NRSEQCONTRATO'],
            'CONTRACT_EXP_ID'    => $variableMeasureRegister['NRVENCPREVCONT'],

            'CDSERVORCA'    => isset($variableMeasureRegister['CDSERVORCA']) ? $variableMeasureRegister['CDSERVORCA'] : null,
            'NMSERVORCA'    => isset($variableMeasureRegister['NMSERVORCA']) ? $variableMeasureRegister['NMSERVORCA'] : null
        );
    }

    protected function buildGeneralCollectionRow($generalCollectionRegister, $log, $product, $userId, $userName, $organizationId, $error) {
        return array (
            'ERROR' => $error,
            'LOG'   => $log,

            'PRODUCT_ID'   	  => $product,
            'OPERATOR_CODE'   => $userId,
            'OPERATOR_NAME'   => $userName,
            'ORGANIZATION_ID' => $organizationId,

            'ID'              => $generalCollectionRegister['ID'],
            'PRODUCT_NAME' 	  => $generalCollectionRegister['NMPRODUTO'],
            'DT_LIMITE'       => $generalCollectionRegister['DT_LIMITE']
        );
    }

    /**
     * @param $variableMeasureRegister
     * @param $organizationId
     * @param $isLogScript
     * @return string
     * @throws \Exception
     */
    protected function execPHPScriptVariableMeasure($variableMeasureRegister, $organizationId, $isLogScript, $product, $primaryId, $orgsAndBranches) {
        $scriptContents   = $isLogScript ? $variableMeasureRegister['PHP_SCRIPT_LOG'] : $variableMeasureRegister['PHP_SCRIPT_COUNT'];
        $contractInitDate = $variableMeasureRegister['DTINICOMPET'];
        $contractEndDate  = $variableMeasureRegister['DTFINCOMPET'];
        $contractId       = $variableMeasureRegister['NRSEQCONTRATO'];
        $serviceId        = isset($variableMeasureRegister['CDSERVORCA']) ? $variableMeasureRegister['CDSERVORCA'] : '';
        $connectionParams = InstanceProvider::getEntityManager()->getConnection()->getParams();
        $connectionParams = json_encode($connectionParams);
        $fileName = $isLogScript ? "/phpFileLog.php" : "/phpFileCount.php";
        $fileName = self::TMP_PATH . $fileName;
        file_put_contents($fileName, $scriptContents);
        $params = " '$connectionParams' '$organizationId' '$contractInitDate' '$contractEndDate' '$contractId' '$product' '$primaryId' '$serviceId' '$orgsAndBranches'";
        $output = trim(shell_exec("php " . $fileName . $params));
        //O "2>&1" serve para retornar o erro caso ocorra, mas com ele estava gerando bug na execução, retornando sempre um COUNT: 0.
        if(empty($output)) {
            $output = trim(shell_exec("php " . $fileName . $params . "2>&1"));
        }
        unlink($fileName);
        return $output;
    }

    /**
     * @param $generalCollectionRegister
     * @param $organizationId
     * @return string
     * @throws \Exception
     */
    protected function execPHPScriptGeneralCollection($generalCollectionRegister, $organizationId) {
        $scriptContents   = $generalCollectionRegister['PHP_SCRIPT_LOG'];
        $connectionParams = InstanceProvider::getEntityManager()->getConnection()->getParams();
        $connectionParams = json_encode($connectionParams);
        $fileName = "/phpFileLog.php";
        $fileName = self::TMP_PATH . $fileName;
        file_put_contents($fileName, $scriptContents);
        $params = " '$connectionParams' '$organizationId' ";
        $output = trim(shell_exec("php " . $fileName . $params));
        //O "2>&1" serve para retornar o erro caso ocorra, mas com ele estava gerando bug na execução, retornando sempre um COUNT: 0.
        if(empty($output)) {
            $output = trim(shell_exec("php " . $fileName . $params . "2>&1"));
        }
        unlink($fileName);
        return $output;
    }

    public function setLogAccess() {
        $environment = InstanceProvider::getEnvironment();
        $logAcessoRepository = InstanceProvider::getLibLogAcessoRepository();
        $organizationId = $environment->getCurrentOrganizationId();
        $userId = $environment->getCurrentUserId();

        $logacesso = $logAcessoRepository->findByOperator($userId, $organizationId);
        if(!empty($logacesso) && $logacesso['DSSISTEMA'] === 'WEB') {
            $logAcessoRepository->update($userId, $organizationId);
        } else {
            $logAcessoRepository->create($userId, 'WEB', $organizationId);
        }
        $logAcessoRepository->updateDtUltAcesOper($userId, $organizationId);
    }
}