<?php

namespace Modules\Connexion\Service;

use Entity\Model\Hastutil;
use Entity\Model\Paravrac;
use Helpers\Outil\Roles;
use Helpers\Outil\Sql;
use Helpers\Session\ParseBase1;
use Helpers\Trad\ITrad;
use Helpers\Trad\Trad;
use Modules\API\APIInterne\Diags\Outil\OutilDiags;
use Modules\Connexion\Repository\ControleConnexionRepo;
use Modules\GlobalApplication\Repository\LicenceOxalys;

class ControleConnexion
{
    private bool $connexion = false;
    private bool $connexionOxaproc = true;
    private bool $connexionSRM = true;
    private bool $connexionMob = true;
    private bool $mobilite = false;

    /**
     * @var array<mixed> $user
     */
    private array $user;

    /**
     * @var array<mixed> $error
     */
    private array $error = [];

    public function __construct(
        private \PDO $pdo,
        private ITrad $trad
    ) {
    }

    /**
     * @param array<mixed> $user
     * @return void
     */
    public function setUser(array $user) : void
    {
        $this->user = $user;
    }

    public function setMobilite(bool $mobilite = false) : void
    {
        $this->mobilite = $mobilite;
    }

    public function connexionOk():bool
    {
        $this->connexionOxaproc         = Sql::toBool($this->user['ACCOXAPR']??false);
        $this->connexionSRM             = Sql::toBool($this->user['ACCOXTRA']??false);
        $this->connexionMob             = Sql::toBool($this->user['ACCMOB']??false) || Sql::toBool($this->user['ACCMPROC']??false);
        
        $this->connexion = true;

        if (strtoupper($this->user['CODE']) != 'OXAUSER') {
            $this->controleEnvironnement();
            $this->controleApplicationClose();
            $this->controleLicence();
        }

        return $this->connexion;
    }

    private function controleEnvironnement():void
    {
        /*
        Contrôle de l’environnement :
        Lecture du type d’environnement du serveur d’application :
        On recherche le fichier « CONFIG_FILE.ini » dans le répertoire « ini » de l’environnement.
        S’il est présent, on recherche, dans la section [GENERAL], les paramètres suivants :
            OXACLOUD : indique une environnement cloud
            ENVTYPE : donne le type d’environnement (‘PROD’ si environnement de production)

        Si le fichier n’est pas trouvé ou s’il ne contient pas le paramètre OXACLOUD, on n’est pas sur un environnement cloud.
        Dans ce cas, on cherche et on lit le fichier « TypeEnvironnement.ini » dans le répertoire ini de l’environnement.
        La ligne « TypeEnvironnement=  vaut « P » pour un environnement de production et « NP » sinon.
        Cas particulier : DV pour env de développement et RC pour env de recette.

        En base de données, on trouve le GUID de la base de données et le type d’environnement de la base de données :
        GUID : SELECT LIB01PARV FROM PARAVRAC WHERE TYPEPARV='PARAMGEN' AND CODEPARV= 'GUIDBDD'
        Type environnement : SELECT LIB01PARV FROM PARAVRAC WHERE TYPEPARV='PARAMGEN' AND CODEPARV= 'TypeEnvironnement'

        Lecture du type d’environnement de la base :

        Cas d’erreur    | Message utilisateur
        Environnement non défini dans la base | Type d'environnement non défini.
        Base prod sur environnement technique non défini |  Base de type "Production" sur environnement non défini.
        Env Prod sur base de données non défini | Environnement de type "Production" sur base de données de type non défini.
        Env Prod sur base de données non production | Incohérence de définition d''environnement : Environnement de type "Production" sur base de données de type "Non Production".
        */
        
        $configFile = $this->parseConfigFile();
        if ($configFile && isset($configFile['GENERAL']['OXACLOUD'])) {
            $environnement = $configFile['GENERAL']['ENVTYPE'] == 'PROD'? 'P':'NP';
        } else {
            $environnement = $this->parseEnvironnement()['TypeEnvironnement'];
        }
        $environnementBDD = Sql::paravrac($this->pdo, 'PARAMGEN', 'TypeEnvironnement');

        if ($environnement == 'P' && $environnementBDD != 'P') {
            $this->error[] = $this->trad->t('Incohérence de définition d\'environnement : Environnement de type "Production" sur base de données de type "Non Production".');
            $this->connexion = false;
        } elseif ($environnement == 'P' && $environnementBDD == '') {
            $this->error[] = $this->trad->t('Environnement de type "Production" sur base de données de type non défini.');
            $this->connexion = false;
        } elseif ($environnementBDD != '' && !$environnementBDD) {
            $this->error[] = $this->trad->t('Base de type "Production" sur environnement non défini');
            $this->connexion = false;
        } elseif ($environnementBDD == '') {
            $this->error[] = $this->trad->t('Type d\'environnement non défini.');
            $this->connexion = false;
        }
    }

    private function controleApplicationClose():void
    {
        $paravrac = (new Paravrac($this->pdo))->find([
            'TYPEPARV'  => 'APPFERMEE',
            'CODEPARV'  => 'O'
        ]);
        if ($paravrac && !Roles::droitsUtilisateur($this->pdo, 'HA_CLOSE')) {
            $this->error[] = $this->trad->t('L\'accès à l\'application est actuellement fermé. Réessayez ultérieurement.');
            $this->connexion = false;
        }
    }

    private function controleLicence():void
    {
        $controleConnexionRepo = new ControleConnexionRepo($this->pdo);
        if ((new LicenceOxalys($this->pdo))->easyDemateActive()) {
            $nombreUser = $controleConnexionRepo->nbUser('PROC')['total'];
            $nombreLicence = (new LicenceOxalys($this->pdo))->licenceEasyDemat();
        } elseif ($this->mobilite) {
            $nombreUser = $controleConnexionRepo->nbUser('MOB')['total'];
            $nombreLicence = (new LicenceOxalys($this->pdo))->licenceMobilite();
        } else {
            $nombreUser  = $controleConnexionRepo->nbUser('PROC')['total'];
            $nombreLicence = (new LicenceOxalys($this->pdo))->licenceOxaproc();
        }

        if ($nombreLicence <= 10) {
            $tolerence = 1;
        } elseif ($nombreLicence < 40) {
            $tolerence = 2;
        } else {
            $tolerence = round($nombreLicence*0.05);
        }

        if ($nombreUser>($nombreLicence+$tolerence)) {
            $this->error[] = $this->trad->t('Connexion impossible : Dépassement de licence. Contactez votre administrateur.');
            $this->connexion = false;
        }
    }

    public function connexionOxaproc():bool
    {
        return $this->connexionOxaproc;
    }

    public function connexionSRM():bool
    {
        return $this->connexionSRM;
    }
    
    public function connexionMobility():bool
    {
        return $this->connexionMob;
    }

    /**
     * @return array<mixed>
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * @return array<mixed>
     */
    private function parseConfigFile()
    {
        
        $pathConfig = (new ParseBase1())->getRep()->envRoot.'/CONFIG_FILE.ini';

        if (!file_exists($pathConfig)) {
            return [];
        }

        $arrayConfigFile = [];
        $keyBloc = '';
        if ($f = fopen($pathConfig, 'r')) {
            //Parse du fichier
            while (!feof($f)) {
                $chTmp = fgets($f, 4096); // on recupére jusqu'à 4096 caractère sur la ligne
                if ($chTmp === false) { // feof return false despite fgets having nothing left to read
                    continue;
                }

                if (strpos($chTmp, '[') === 0) {
                    $keyBloc = str_replace('[', '', $chTmp);
                    $keyBloc = str_replace(']', '', $keyBloc);
                    $keyBloc = trim($keyBloc);
                } else {
                    $line = explode('=', $chTmp);
                    $arrayConfigFile[$keyBloc][trim($line[0])] = trim($line[1]);
                }
            }
        }

        return $arrayConfigFile;
    }

    /**
     * @return array<mixed>
     */
    private function parseEnvironnement()
    {
        $pathConfig = (new ParseBase1())->getRep()->envRoot.'/TypeEnvironnement.ini';

        $arrayConfigFile = [];
        if ($f = fopen($pathConfig, 'r')) {
            //Parse du fichier
            while (!feof($f)) {
                $chTmp = fgets($f, 4096); // on recupére jusqu'à 4096 caractère sur la ligne
                if ($chTmp === false) { // feof return false despite fgets having nothing left to read
                    continue;
                }
                $line = explode('=', $chTmp);
                $arrayConfigFile[trim($line[0])] = trim($line[1]);
            }
        }

        return $arrayConfigFile;
    }
}
