<?php
namespace Modules\API\APIInterne\Mail\Controller;

use Entity\Model\Alias\ParamImap;
use Entity\Model\Hastutil;
use Entity\Model\MailSuivi;
use Entity\Model\ParamDico;
use Entity\Model\Paravrac;
use GuzzleHttp\Psr7\Response;
use Helpers\Log\LogSysteme;
use Helpers\Fichier\Fichier;
use Helpers\Outil\Outils;
use Helpers\Outil\Sql;
use Psr\Http\Message\ResponseInterface;
use Skeleton\Controller\Controller;

class MailController extends Controller
{

    /**
     * unitaireAction
     *
     * @return string
     */
    public function unitaireAction(): string
    {
        $type = $this->request->getAttribute('type');
        $ID = $this->request->getAttribute('id');
        
        $_SESSION['contextMailAsync'] = false;

        /**
         * send mail without Asynchrone
         */
        if ($this->contenaire->has('Specifique.Param.MailAsynchroneActive')
            && !$this->contenaire->get('Specifique.Param.MailAsynchroneActive')
            ) {
            return $this->dispatcher($ID);
        }
        
        set_time_limit(40);

        if ($type == 'synchrone') {
            return $this->dispatcher($ID);
        } else {
            $_SESSION['contextMailAsync'] = true;

            Fichier::appelGetAsyncExport(
                Outils::getRootUrl()
                . '/'
                . $this->router->generateUri(
                    'API.Mail.asynchroneMail',
                    ['id' => $ID]
                ),
                []
            );

            return 'Statut|IN PROGRESS|';
        }
    }

    public function asynchroneMailAction(): string
    {

        set_time_limit(40);
        $ID = $this->request->getAttribute('id');
        return $this->dispatcher($ID);
    }


    public function imapConnectionCheckAction(): Response
    {
        $listConfig = (new ParamImap($this->pdo))->listImapConfig();

        $res = [];
        foreach ($listConfig as $config) {
            $subcontroller = $this->getSubController($config->type);
            try {
                $subcontroller->testEmailReadConnection($config);
            } catch (\Exception $e) {
                LogSysteme::prefixErrorLog($e);
                $res[] = [
                    'id' => $config->id,
                    'label' => $config->label,
                    'status' => 1,
                    'status_label' => 'Error',
                    'error' => $e->getMessage(),
                ];
                continue;
            }
            $res[] = [
                'id' => $config->id,
                'label' => $config->label,
                'status' => 0,
                'status_label' => 'Connection successfull',
            ];
        }


        $status = array_reduce($res, function (bool $carry, array $item) {
            if ($item['status'] !== 0) {
                return false;
            }
            return $carry;
        }, true) ? 0 : 1;
        $payload = [
            'status' => $status,
            'status_label' => $status == 0 ? 'Connection successfull' : 'Error',
            'list_imap' => $res,
        ];

        $accept = $this->request->getHeaders()['Accept'][0];
        if (str_contains($accept, 'text/xml')) {
            return $this->createXmlResponse($payload);
        }

        return $this->createJsonResponse($payload);
    }



    //_____________________________________________________________________________
// Process

    public function dispatcher(string $ID): string
    {
        $password = '';
        $username = '';
        $paravrac = new Paravrac($this->pdo);

        $paramDico = Sql::paramDicoAllCol($this->pdo, 'MAIL_REQUEST', $ID);

        if (!$paramDico) {
            return '<?xml version="1.0" encoding="iso-8859-1" standalone="no" ?>
                <Relais_HTTP_Out>
                  <Statut>E</Statut>
                  <Message>Le token n\'est pas présent.</Message>
                  <FicRep></FicRep>
                </Relais_HTTP_Out>';
        }

        $mailSuivi = new MailSuivi($this->pdo);
        $infoMail = $mailSuivi->find($paramDico['ALPHA1']);
        // Nettoyage des adresses email dans ['EMAIL_TO'] et ['EMAIL_REPLY_TO']
        $emailTo = array_map('trim', explode(',', $infoMail['EMAIL_TO'] ?? ''));
        $emailReplyTo = array_map('trim', explode(',', $infoMail['EMAIL_REPLY_TO'] ?? ''));

        $infoMail['EMAIL_TO'] = implode(',', $emailTo);
        $infoMail['EMAIL_REPLY_TO'] = implode(',', $emailReplyTo);

        /**
         *  GESTION DU USER ET MDP
         */

        $user = [];
        if (trim($infoMail['CODE_USER']) != '') {
            $user = (new Hastutil($this->pdo))->find(['CODE' => $infoMail['CODE_USER']]);
        }

        $paramCtr = $this->getParamForCodeCtr($user['CTR_ADR'] ?? '');
        $paramSoc = $this->getParamForCodeSoc($user['CODE_STE'] ?? '');

        // Test si il y a un paramettrage société ou centre ou central
        if (is_array($paramCtr) && count($paramCtr) && trim($paramCtr['ServSMTP']) != '') {
            $host = $paramCtr['ServSMTP'];
            $port = $paramCtr['PortSmtp'];

            $parametreOauth2 = $paramCtr;
        } elseif (is_array($paramSoc) && count($paramSoc) && trim($paramSoc['ServSMTP']) != '') {
            $host = $paramSoc['ServSMTP'];
            $port = $paramSoc['PortSmtp'];

            $parametreOauth2 = $paramSoc;
        } else {
            $host = $paravrac->getGeneric('MSGSMTPSRV') ?? '';
            $port = $paravrac->getGeneric('MSGSMTPPORT') ?? '';
            $parametreOauth2 = \Helpers\Outil\Sql::getArrayHorizontalByKey(
                (new \Modules\API\APIInterne\Mail\Repository\Mail($this->pdo))->getAllParamOauth2Standard(),
                'CODEPARV',
                'LIB01PARV'
            );
        }

        if (is_array($paramCtr) && count($paramCtr) && ($paramCtr['ADRORIIMP'] == 'O' || $user['USRMSG'] == '')) {
            if ((isset($paramCtr['USRSERV']) && $paramCtr['USRSERV'] != '')) {
                $username = $paramCtr['USRSERV'];
            }
            if ((isset($paramCtr['PWDSERV']) && $paramCtr['PWDSERV'] != '')) {
                $password = $paramCtr['PWDSERV'];
            }
        } elseif (is_array($paramSoc) && count($paramSoc) && ($paramSoc['ADRORIIMP'] == 'O' || $user['USRMSG'] == '')) {
            if ((isset($paramSoc['USRSERV']) && $paramSoc['USRSERV'] != '')) {
                $username = $paramSoc['USRSERV'];
            }
            if ((isset($paramSoc['PWDSERV']) && $paramSoc['PWDSERV'] != '')) {
                $password = $paramSoc['PWDSERV'];
            }
        } else {
            if ($paravrac->getGeneric('TypeEnvironnement') == 'NP'
                || $paravrac->getGeneric('MSGORIMAILIMP') == 'O'
                || trim($infoMail['CODE_USER']) == ''
                || (isset($user['USRMSG']) && $user['USRMSG'] == '')
                || !isset($user['USRMSG'])
            ) {
                $msgSmtpLogin = $paravrac->getGeneric('MSGSMTPLOGIN');
                if (!empty($msgSmtpLogin)) {
                    $username = $msgSmtpLogin;
                }
                $msgSmtpPass = $paravrac->getGeneric('MSGSMTPPWD');
                if (!empty($msgSmtpPass)) {
                    $password = $msgSmtpPass;
                }
            } else {
                if ($user['USRMSG'] != '') {
                    $username = $user['USRMSG'];
                }
                if ((isset($user['MDPMSG']) && $user['MDPMSG'] != '')) {
                    $password = $user['MDPMSG'];
                }
            }
        }

        $subcontroller = $this->getSubController(intval($parametreOauth2['OAUTH2_TYPE_AUTH']));

        return $subcontroller->mailEnvoi(
            $ID,
            false,
            $paravrac,
            $username,
            $password,
            $host,
            $port,
            $infoMail,
            $parametreOauth2,
            $paramDico
        );
    }

    //_____________________________________________________________________________
// Sub-routine

    private function getSubController(int $id): AbsMailController
    {
        switch ($id) {
            case 1:
                return new MicrosoftController(
                    $this->contenaire->get(\Skeleton\Renderer\RendererInterface::class),
                    $this->contenaire->get(\PDO::class),
                    $this->contenaire->get(\Skeleton\Router::class),
                    $this->contenaire->get(\Psr\Container\ContainerInterface::class)
                );

            case 2:
                return new GoogleController(
                    $this->contenaire->get(\Skeleton\Renderer\RendererInterface::class),
                    $this->contenaire->get(\PDO::class),
                    $this->contenaire->get(\Skeleton\Router::class),
                    $this->contenaire->get(\Psr\Container\ContainerInterface::class)
                );
            default:
        }
        return new StandardController(
            $this->contenaire->get(\Skeleton\Renderer\RendererInterface::class),
            $this->contenaire->get(\PDO::class),
            $this->contenaire->get(\Skeleton\Router::class),
            $this->contenaire->get(\Psr\Container\ContainerInterface::class)
        );
    }


    /**
     * Repository
     */

    /**
     * getParamForCodeCtr
     *
     * @param  string $id
     * @return array<mixed>
     */
    public function getParamForCodeCtr(string $id)
    {
        $req = "  SELECT ADRSERV ServSMTP, 
                    PORTSERV PortSmtp,
                    USRSERV,
                    PWDSERV,
                    ADRORI AdresseFrom, 
                    ADRORIIMP FromImpose,
                    OAUTH2_C_ID,
                    OAUTH2_C_SID,
                    OAUTH2_REFRESH_TOKEN,
                    OAUTH2_SCOPE,
                    OAUTH2_TYPE_AUTH,
                    OAUTH2_URL_AUTH,
                    OAUTH2_URL_TOKEN
                FROM PARMAICTR with(nolock)
                WHERE CODECTR=:CODECTR ";

        $arrayReq = [':CODECTR' => $id];

        $req = $this->pdo->prepare($req);
        $req->execute($arrayReq);

        return $req->fetch();
    }


    /**
     * getParamForCodeSoc
     *
     * @param  string $id
     * @return array<mixed>
     */
    public function getParamForCodeSoc(string $id)
    {
        $req = "  SELECT ADRSERV ServSMTP, 
                    PORTSERV PortSmtp,
                    USRSERV,PWDSERV,
                    ADRORI AdresseFrom, 
                    ADRORIIMP FromImpose,
                    OAUTH2_C_ID,
                    OAUTH2_C_SID,
                    OAUTH2_REFRESH_TOKEN,
                    OAUTH2_SCOPE,
                    OAUTH2_TYPE_AUTH,
                    OAUTH2_URL_AUTH,
                    OAUTH2_URL_TOKEN
                FROM PARMAISOC with(nolock)
                WHERE CODESOC=:CODESOC ";

        $arrayReq = [':CODESOC' => $id];

        $req = $this->pdo->prepare($req);
        $req->execute($arrayReq);

        return $req->fetch();
    }

    /**
     * createJsonResponse
     *
     * @param  array<mixed> $data
     * @param  int $status
     */
    protected function createXmlResponse(array $data, int $status = 200): Response
    {

        // creating object of SimpleXMLElement
        $xml_data = new \SimpleXMLElement('<?xml version="1.0"?><root></root>');

        // function defination to convert array to xml
        self::arrayToXml($data, $xml_data);

        return new Response(
            $status,
            ['Content-Type' => 'text/xml'],
            $xml_data->asXML()
        );
    }

    /**
     * @param array<mixed> $data
     */
    private static function arrayToXml(array $data, \SimpleXMLElement &$xml_data): void
    {
        foreach ($data as $key => $value) {
            if (is_array($value)) {
                if (is_numeric($key)) {
                    $key = 'item'; //dealing with <0/>..<n/> issues
                }
                $subnode = $xml_data->addChild($key);
                /**  */
                self::arrayToXml($value, $subnode);
            } else {
                $xml_data->addChild("$key", htmlspecialchars("$value"));
            }
        }
    }
}
