<?php

namespace Modules\Evaluation\Service;

use Entity\Model\CampEnt;
use Entity\Model\CampEve;
use Entity\Model\CampNotex;
use GuzzleHttp\Psr7\Response;
use Helpers\Outil\Date;
use Helpers\Outil\Mail;
use Helpers\Trad\ITrad;
use Helpers\Trad\Trad;
use Modules\Evaluation\MenuContextuel\CampaignMenuContextuel;
use Modules\Evaluation\Repository\Campaign;
use Modules\Evaluation\Repository\Rater;
use PDO;
use Psr\Container\ContainerInterface;
use Skeleton\Router;

class CampaignService
{
    private PDO $pdo;
    private ITrad $trad;
    /**
     * @var mixed $pdoStorage
     */
    private $pdoStorage;

    /**
     * @var mixed $pdoWithoutODBC
     */
    private $pdoWithoutODBC;


    private Campaign $campaignRepository;
    /**
     * __construct
     *
     * @param  mixed $pdoStorage
     * @param  mixed $pdoWithoutODBC
     */
    public function __construct(PDO $pdo, ITrad $trad, $pdoStorage = null, $pdoWithoutODBC = null)
    {
        $this->pdo = $pdo;
        $this->pdoStorage = $pdoStorage;
        $this->pdoWithoutODBC = $pdoWithoutODBC;
        $this->trad = $trad;
        $this->campaignRepository = new Campaign($this->pdo, $this->pdoStorage, $this->pdoWithoutODBC);
    }

    /**
     * campaignDetail
     *
     * @param  int $id
     * @param  Router $router
     * @param  array<mixed> $rights
     * @return array<mixed>
     */
    public function campaignDetail(int $id, Router $router, array $rights)
    {
        $campaign = $this->campaignRepository->campaignDetail($id);

        switch ($campaign['STATUT']) {
            case 'E':
                if (($campaign['DTEFIN_PREVUE'] . $campaign['HEUREFIN_PREVUE']) <= \date('YmdHis')) {
                    $campaign['LIBSTATUT'] = $this->trad->t('En attente de clôture');
                } else {
                    $campaign['LIBSTATUT'] = $this->trad->t('En cours');
                }
                break;
            case 'D':
                $campaign['LIBSTATUT'] = $this->trad->t('Notation dépouilleur');
                break;
            case 'N':
                $campaign['LIBSTATUT'] = $this->trad->t('Notation terminée');
                break;
            case 'T':
                $campaign['LIBSTATUT'] = $this->trad->t('Terminée');
                break;
            case 'P':
                $campaign['LIBSTATUT'] = $this->trad->t('Préparation');
                break;
            default:
                $campaign['LIBSTATUT'] = '';
                break;
        }

        $menuContextuel   = new CampaignMenuContextuel($this->pdo, $router, $this->trad, $rights);
        $campaign['menuContextuel'] = $menuContextuel->generateHeading($campaign);

        return $campaign;
    }

    /**
     * getExternalRatersNames
     *
     * @param  array<mixed> &$raters
     * @return void
     */
    public function getExternalRatersNames(array &$raters): void
    {
        $namesTmp = (new CampNotex($this->pdo))
            ->fetchAll(['ID_NOTEUR', 'NOM_NOTEUR'], [], PDO::FETCH_ASSOC);

        $names = [];
        foreach ($namesTmp as $name) {
            $names[$name['ID_NOTEUR']] = $name['NOM_NOTEUR'];
        }

        foreach ($raters as &$rater) {
            $rater = $names[$rater];
        }
    }

    /**
     * gestionErrorValidationCampaign
     *
     * @param  mixed $erreurReturn
     * @param  mixed $traduction
     * @param  mixed $erreurCode
     * @return array<mixed>
     */
    public function gestionErrorValidationCampaign($erreurReturn, $traduction, $erreurCode)
    {
        $erreurNonBloquant = '';
        $erreurBloquant = '';
        $statutErrorGlobal = '';

        foreach ($erreurReturn as $erreur) {
            if (($erreur['BLOQUANT'] ?? '') == 'N') {
                $statutErrorGlobal = 'B';
                switch ($erreurCode) {
                    case '5':
                        $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['theme'] ?? $erreur['LIB_THEME'], $erreur['fournisseur'] ?? '') . '<br/>';
                        break;
                    case '6':
                        $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['question'] ?? $erreur['LIB_QUEST'], $erreur['theme'] ?? $erreur['LIB_THEME']) . '<br/>';
                        break;
                    case '7':
                        $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['question'] ?? $erreur['LIB_QUEST'], $erreur['theme'] ?? $erreur['LIB_THEME'], $erreur['fournisseur'] ?? '') . '<br/>';
                        break;
                    case '8':
                        $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['question'] ?? $erreur['LIB_QUEST'], $erreur['theme'] ?? $erreur['LIB_THEME']) . '<br/>';
                        break;
                }
            } else {
                switch ($erreurCode) {
                    case '5':
                        $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['theme'] ?? $erreur['LIB_THEME'], $erreur['fournisseur'] ?? '') . '<br/>';
                        break;
                    case '6':
                        $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['question'] ?? $erreur['LIB_QUEST'], $erreur['theme'] ?? $erreur['LIB_THEME']) . '<br/>';
                        break;
                    case '7':
                        if ($erreur['TYPE'] == 'C') {
                            $erreurNonBloquant .= Trad::strBuild($this->trad->t('La question "@1@" dans le thème @2@ pour le fournisseur @3@ ne renvoie aucun résultat.'), $erreur['question'] ?? $erreur['LIB_QUEST'], $erreur['theme'] ?? $erreur['LIB_THEME'], $erreur['fournisseur'] ?? '') . '<br/>';
                        } else {
                            $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['question'] ?? $erreur['LIB_QUEST'], $erreur['theme'] ?? $erreur['LIB_THEME'], $erreur['fournisseur'] ?? '') . '<br/>';
                        }
                        break;
                    case '8':
                        $erreurNonBloquant .= Trad::strBuild($traduction, $erreur['question'] ?? $erreur['LIB_QUEST'], $erreur['theme'] ?? $erreur['LIB_THEME']) . '<br/>';
                        break;
                }
                $statutErrorGlobal = 'B';
            }
        }

        return [
            'erreurNonBloquant' => $erreurNonBloquant,
            'erreurBloquant' => $erreurBloquant,
            'statutErrorGlobal' => $statutErrorGlobal,
        ];
    }

    /**
     * sendMailToRaters
     * gère l'envoi de mails aux évaluateurs d'une campagne via appel à un wsdl
     *
     * @param  int $campaignId
     * @param  array<mixed> $ratersExterne
     * @param  ContainerInterface $contenaire
     * @param  Router $router
     * @param  string $keyJWT
     * @param  bool $relance
     * @return array<mixed>
     */
    public function sendMailToRaters($campaignId, $contenaire, $router, array $ratersExterne = [], $keyJWT = '', $relance = false)
    {
        $trad = $contenaire->get(ITrad::class);
        // on récupère les infos concernant le créateur de la campagne, qui sera l'émetteur du mail
        $campaignRepo = new Campaign($this->pdo);
        $campEnt = new CampEnt($this->pdo);
        $emailSender = $campaignRepo->getValidationEmailSender($campaignId);

        // le code mail dépend du contexte : s'il s'agit d'une validation ou d'une relance des évaluateurs
        $codeMail = $relance ? 'CAMP_EVAL_REL_NOT' : 'CAMP_EVAL_NOT';

        if (count($ratersExterne)) {
            $raters = $ratersExterne;
        } else {
            // on récupère la liste des évaluateurs de la campagne, destinataires du mail
            $raterRepo = new Rater($this->pdo, $this->pdoStorage);

            // d'abord les évaluateurs des questions qui ne sont pas adressées aux fournisseurs
            $raters = $raterRepo->getRatersForEmailByCampaign($campaignId);

            // puis les évaluateurs des questions adressées aux fournisseurs (dépouilleur si non référencé oxalink ou contact fournisseur pour les fournisseurs oxalink)
            $supplierRaters = $raterRepo->getSupplierRatersForEmailByCampaign($campaignId);

            if (count($supplierRaters) > 0) {
                $raters = array_merge($raters, $supplierRaters);
            }
        }

        // tableau qui sera chargé de recueillir la liste des évaluateurs dont l'adresse email n'est pas enregistrée en base
        $missingRaters = [];
        
        $campaign = $campEnt->find(['ID_CAMP' => $campaignId], [], [], PDO::FETCH_ASSOC);

        // pour chacun d'eux on envoie un mail via wsdl
        foreach ($raters as $rater) {
            if (!isset($rater['EMAIL']) || $rater['EMAIL'] == '') {
                $missingRaters[] = $rater;
            } else {
                if (!isset($rater['LINK']) && $rater['ORIGIN'] == 'E') {
                    $payload = [
                        'ID_NOTEUR' => $rater['COD_NOTEUR'],
                        'EMAIL_NOTEUR' => $rater['EMAIL'],
                        'exp' => time() + 60 * 60 * 60 * 60
                    ];

                    $url =  $_SERVER['HTTP_ORIGIN'] . $router->generateUri('Evaluation.Evaluation.index', ['jwt' => \Firebase\JWT\JWT::encode($payload, $keyJWT, 'HS256')]);
                } elseif (!isset($rater['LINK']) && $rater['ORIGIN'] == 'I') {
                    $url = $contenaire->get('urlOxaproc') . '/index';
                } elseif (!isset($rater['LINK']) && $rater['ORIGIN'] == 'F') {
                    $url = $contenaire->get('urlOxaLinkIndex') . '/index.php';
                }

                if ($relance) {
                    // on crée un évènement Relance dans les évènements de la campagne
                    if ($rater['ORIGIN'] == 'E') {
                        $dataResume = $rater['NOM'] ?? '' . ' (' . $rater['EMAIL'] . ') ';
                    } else {
                        $dataResume = $rater['NOM'] ?? '' . ' (' . $rater['COD_NOTEUR'] . ') ';
                    }
                    $this->campaignRepository->eventMultiInsert($campaignId, 'REL', [
                        'COMMENTAIRE'   => Trad::strBuild($trad->t('Relance de @1@'), $dataResume),
                    ]);
                }
                
                $mailInfo = [
                    'LIBELLE_CAMPAGNE'    => $campaign['LIBELLE'],
                    'CREATEUR_CAMPAGNE'   => $emailSender['NOM'] == '' ? ' ' : $emailSender['NOM'],
                    'FONCTION_CREATEUR'   => $emailSender['FONCTION'] ?? '',
                    'URL'                 => $rater['LINK'] ?? ($url ?? ''),
                    'DATE_DEB'            => Date::dateConverte($campaign['DTEDEB_PREVUE'], 'jj/mm/aaaa') . ' ' . Date::heureConverte($campaign['HEUREDEB_PREVUE']),
                    'DATE_FIN'            => Date::dateConverte($campaign['DTEFIN_PREVUE'], 'jj/mm/aaaa') . ' ' . Date::heureConverte($campaign['HEUREFIN_PREVUE']),
                ];
                
                Mail::generateMail(
                    $this->pdo,
                    $this->trad,
                    $rater['EMAIL'],
                    $codeMail,
                    $rater['COD_LNG'],
                    $mailInfo
                );
            }
        }

        return $missingRaters;
    }

    /**
     * closeCampaign
     *
     * @param  string $id
     * @param  bool $confirm
     * @return array<mixed>
     */
    public function closeCampaign(string $id, bool $confirm = false)
    {
        return $this->campaignRepository->closeCampaign($id, $confirm);
    }

    /**
     * validationCampaign
     *
     * @param  string $id
     * @param  bool $confirm
     * @return array<mixed>
     */
    public function validationCampaign(string $id, bool $confirm = false)
    {
        return $this->campaignRepository->validationCampaign($id, $confirm);
    }

    /**
     * @return array<mixed>
     */
    public function devaliderCampagne(string $id)
    {
        return $this->campaignRepository->devalidCampagne($id);
    }
}
