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

use Firebase\JWT\Key;
use GuzzleHttp\Utils;
use Helpers\Log\LogSysteme;
use Helpers\Session\ParseBase1;
use Modules\API\APIInterne\OxaMobility\Outil\ApiRequest;
use Skeleton\Controller\Controller;
use GuzzleHttp\Psr7\Response;
use Helpers\Fichier\Fichier;
use Helpers\Outil\HTTP;
use Helpers\Trad\Trad;
use Helpers\Webservice\MagicDispatcher;
use Modules\API\APIInterne\OxaMobility\Outil\OxaMobility;
use Modules\Index\Outil\OutilConnexion;
use Psr\Http\Message\ResponseInterface;

class DispatcherController extends Controller
{
    protected mixed $body;
    /** @var array<mixed> */
    protected array $jwtPayload;
    protected bool $json;
    protected string $controller;
    protected string $action;

    public function init() :?Response
    {
        $post = [];
        
        /**
         * CSRF prise en compte du token car déjà controlé car token déjà existant dans l'appel
         */
        $_POST['tokenCSRF'] = \Helpers\Securite\Securite::creationTokenCSRF();
        
        
        $this->controller = \strtoupper($this->request->getAttribute('controller'));
        $this->action = \strtoupper($this->request->getAttribute('action'));
        
        $return['MsgErreur'] = '';
        
        $HTTP_RAW_POST_DATA = Fichier::fileGetContents("php://input");
        OxaMobility::getBodyAndSplitVar($HTTP_RAW_POST_DATA, $post);
        

        $modeV1 = false;
        if (\Helpers\Outil\Outils::isJson($HTTP_RAW_POST_DATA)) {
            $this->json = true;
            $this->body = json_decode($HTTP_RAW_POST_DATA, true)['MPROC_In'];
        } else {
            $this->json = false;
            /** @var \SimpleXMLElement $xml */
            $xml = @simplexml_load_string((string) str_replace('xmlns:', '', $HTTP_RAW_POST_DATA));
            $HTTP_RAW_POST_DATATmp = $HTTP_RAW_POST_DATA;
            $HTTP_RAW_POST_DATA = Utils::jsonEncode($xml);
            $this->body = Utils::jsonDecode($HTTP_RAW_POST_DATA, true);
            if ($this->controller == '') {
                /** @phpstan-ignore-next-line */
                if (!isset($this->body['Action']) && isset($this->body['SOAP-ENV:Body']['OxaprocIN'])) {
                    $modeV1 = true;
                    $this->controller = 'MOBILITE_V1';
                    foreach ($this->body['SOAP-ENV:Body']['OxaprocIN'] as $k => $block) {
                        if ($k == '@attributes') {
                            $this->body[array_key_first($block)] = $block[array_key_first($block)];
                        } elseif ($k != '@attributes') {
                            $this->action = $k;
                            $this->body['Action'] = $k;
    
                            foreach ($block as $ktag => $tag) {
                                $this->body[$ktag] = $tag;
                            }
    
                            break;
                        }
                    }
    
                    unset($this->body['@attributes']);
                    unset($this->body['SOAP-ENV:Body']);
                }
            }
        }

        if (!isset($this->body['token']) && isset($_SERVER['HTTP_X_OXA_TOKEN'])) {
            $this->body['token'] = $_SERVER['HTTP_X_OXA_TOKEN'];
        }
       
        if (!isset($this->body['token']) && (!isset($post['METHOD_OXAPROC']) || $post['METHOD_OXAPROC']!= 'OXAPRC_TSTBROKER')) {
            $return['MsgErreur']= 'il manque la balise <token>, enfant de la balise MPROC_In|OxaprocIN';
        }

        if (isset($this->body['Action'])) {
            if (isset($this->body['@attributes']['LngUtilisation']) || !isset($this->body['LngUtilisation'])) {
                $return['MsgErreur']= 'il manque la balise <LngUtilisation>, enfant de la balise MPROC_In';
            }
    
            if (isset($this->body['@attributes']['MprocVers']) || !isset($this->body['MprocVers']) && $modeV1 == false) {
                $return['MsgErreur']= 'il manque la balise <MprocVers>, enfant de la balise MPROC_In';
            }
            
            if ((new ParseBase1())->getDebug()) {
                if ($this->json == true) {
                    Fichier::createFichierTmp(LogSysteme::getServerName().'.'.str_replace('|', '_', $this->body['Action']).'_In.json', $return['MsgErreur']." ".file_get_contents("php://input"));
                } else {
                    Fichier::createFichierTmp(LogSysteme::getServerName().'.'.str_replace('|', '_', $this->body['Action']).'_In.xml', $return['MsgErreur']." ".file_get_contents("php://input"));
                }
            }
        }

        if (!isset($post['METHOD_OXAPROC']) || $post['METHOD_OXAPROC']!= 'OXAPRC_TSTBROKER') {
            try {
                $verify = \Firebase\JWT\JWT::decode(trim($this->body['token']), new Key($this->JWTKEY, 'HS256'));
            } catch (\Exception $e) { // Also tried JwtException
                $return['MsgErreur']= $e->getMessage();
            }
        }

        if ($return['MsgErreur'] != '') {
            $return['Statut'] = 'E';
            if ($this->json) {
                $retourJSON['MPROC_Out'] = $return;
                header('content-type:application/json');
                
                return (new Response(403, [], (string)json_encode($retourJSON)));
            }
            
            
            $xml = new \SimpleXMLElement('<MPROC_Out/>');
            header('Content-Type: application/xml; charset=utf-8');
            \Helpers\Outil\Outils::array_to_xml($return, $xml);
            $domxml = new \DOMDocument('1.0');
            $domxml->preserveWhiteSpace = false;
            $domxml->formatOutput = true;
            $domxml->loadXML($xml->asXML());
            /** @phpstan-ignore-next-line */
            return (new Response(403, [], $domxml->saveXML()));
        }
        

        $this->jwtPayload = (array) ($verify ?? []);
        
        if ($modeV1 == false && $this->controller == '' && !empty($post['PRGNAME'])) {
            $contents = file_get_contents(session_save_path().'\\sess_'.$this->jwtPayload['sessionId']);
            session_name('__OxaProc-PHPSESSID');
            @session_start();
            session_decode((string)$contents);
            $magicDispatcher = new MagicDispatcher('Oxaproc_Gen.wsdl', $post['METHOD_OXAPROC'], $post['content'], false, false, $post['PRGNAME'], $post['appname']);
            echo $magicDispatcher->getResult();
            return (new Response())->withStatus(200, $magicDispatcher->getResult());
        }
        return null;
    }

    /**
     * @return mixed
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function dispatcherAction()
    {
        $contents = file_get_contents(session_save_path() . '\\sess_' . $this->jwtPayload['sessionId']);
        @session_name('__OxaProc-PHPSESSID');
        @session_start();
        session_decode((string)$contents);

        if ($this->controller!= '') {
            $action = [
                '0' => $this->controller,
                '1' => $this->action,
            ];
        } else {
            $action = explode('|', $this->body['Action']);
        }

        $trad = $this->getTranslationService();
        
        if ($trad instanceof Trad) {
            $_SESSION['Session_Langue'] = $this->body['LngUtilisation'];
            $trad->setLang($_SESSION['Session_Langue']);
        }
        
        $outilConnexion = new OutilConnexion($this->pdo, $this->pdoOxaFT, $this->contenaire);
        $outilConnexion->getEnv();
        
        /** @var class-string<AbsApiController> */
        $class =  "\\Modules\\API\\APIInterne\\OxaMobility\\Controller\\".$action[0]."Controller";
        $execution = new $class(
            $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)
        );
        $execution->setRequest(new ApiRequest($this->request, [
            'body' => $this->body,
            'jwtPayload' => $this->jwtPayload,
            'json' => $this->json,
        ]));
        
        if (method_exists($execution, 'init')) {
            $responseInit = $execution->init();

            if ($responseInit instanceof ResponseInterface) {
                return $responseInit;
            }
        }
        return $execution->{$action[1]."Action"}($this->body, $this->jwtPayload, $this->json);
    }

    // public static function camelCase($str, array $noStrip = [])
    // {
    //         // non-alpha and non-numeric characters become spaces
    //         $str = (string) preg_replace('/[^a-z0-9' . implode("", $noStrip) . ']+/i', ' ', $str);
    //         $str = trim($str);
    //         // uppercase the first character of each word
    //         $str = ucwords($str);
    //         $str = (string)str_replace(" ", "", $str);
    //         $str = lcfirst($str);

    //         return $str;
    // }
}
