<?php
namespace Modules\Utilisateur\Controller;

use Entity\Model\Etatfiltre;
use Entity\Model\EtatStat;
use Entity\Model\Periodes;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Utils;
use Helpers\ChampsSupplementaire\ChampSupp;
use Helpers\Log\LogSysteme;
use Helpers\Outil\Roles;
use Helpers\Outil\Sql;
use Helpers\Validator\Validator;
use Modules\Evaluation\Data\Parametre;
use Modules\Fournisseur\Repository\Indicateur;
use Modules\Utilisateur\Repository\etatTableauDeBord;
use Skeleton\Controller\Controller;
use Helpers\Session\ParseBase1;

class KpiDashboardController extends Controller
{
    public function indexAction() : string
    {
        $periode = $this->request->getQueryParams()['periode'] ?? null;
        $listKpi = (new EtatStat($this->pdo))->findAll([
            'SOURCE' => 'OXACHARTS',
        ]);
        //(new etatTableauDeBord($this->pdo))->listeEtatUserTB();
        
        $trad = $this->getTranslationService();


        foreach ($listKpi as &$kpi) {
            $kpi['type'] = $this->getKpiType($kpi['CODETAT']);
        }

        $listTbchart = (new etatTableauDeBord($this->pdo))->listeTbchartEtat();

        $listPeriodes = (new Indicateur($this->pdo))->periodedispo();
        $currentPeriode = $periode ?? reset($listPeriodes)['CODE_PER'];

        return $this->renderer->render('@Utilisateur/Dashboard/dashboard', [
            'hasBackup' => Roles::droitsUtilisateur($this->pdo, 'OX_AF_BACK'),
            'listeTaille' => ['P' => $trad->t('Petit'), 'G' => $trad->t('Grand')],
            'listKpi' => $listKpi,
            'periodes' => $listPeriodes,
            'periodesCurrent' => $currentPeriode,
            'listChart' => array_map(function ($tbchartEtat) use ($currentPeriode) {
                return [
                    'kpiId' => $tbchartEtat['CODE_ETAT'],
                    'listFiltre' => $tbchartEtat['listFiltre'],
                    'content' => $this->getWsdlChartContent(
                        $tbchartEtat['CODE_ETAT'],
                        ['PERIODES' => $currentPeriode]
                        + array_column(
                            $tbchartEtat['listFiltre'],
                            'VALFILTRE',
                            'CODFILTRE'
                        )
                    ),
                ];
            }, $listTbchart)
        ]);
    }

    public function ajaxInputDetailAction() : string
    {
        $code_etat = $this->request->getAttribute('codEtat');
        $post       = $this->request->getParsedBody();
        $modeSelect = $post['modeSelect'];
        $idSelect   = $post['idSelect'];
        
        $idExplod = explode('separateurFiltre', $idSelect);

        $repositoryEtatStatistique = new \Modules\EtatStatistiques\Repository\EtatStat($this->pdo);
        $filtre = $repositoryEtatStatistique->getTypeAffichageInput($code_etat, $idExplod[0]);

        $champSupp = new ChampSupp($this->pdo);
        $inputGenerate = $champSupp->generateImput(
            $this->router,
            $this->getTranslationService(),
            $filtre['CODE_FILTRE']
        );

        return $this->renderer->render('@EtatStatistiques/gestion-stat/ajax_inputEtat', [
            'filtre' => $filtre,
            'codeEtat' => $idExplod[0],
            'modeSelect' => $modeSelect,
            'inputGenerate' => $inputGenerate,
        ]);
    }

    public function formKpiAction() :string
    {
        $code_etat = $this->request->getAttribute('kpiId');
        $post = $this->request->getParsedBody();
        $uid = $this->request->getQueryParams()['uid'] ?? '';
        $periode = $this->request->getQueryParams()['periode'] ?? null;
        $isEdit = !empty($this->request->getQueryParams()['edit'] ?? null);

        // Fail-safe
        if ($periode === null) {
            $listPeriodes = (new Indicateur($this->pdo))->periodedispo();
            $periode = reset($listPeriodes)['CODE_PER'];
        }

        return $this->renderer->render('@Utilisateur/Dashboard/popupKpiParam', [
            'uid' => $uid,
            'kpiId' => $code_etat,
            'form' => $this->createKpiFormEditor($code_etat, $post),
            'periode' => $periode,
            'isEditMode' => $isEdit
        ]);
    }
    
    public function updateUserListKpiAction() :Response
    {
        $post = $this->request->getParsedBody();
        $validator = $this->createValidator();

        $post['listKpi'] = $post['listKpi'] ?? [];

        // Fail-safe: check code etat exists
        $listCodeEtat = array_column($post['listKpi'], 'CODE_ETAT');
        if (! empty($listCodeEtat)) {
            $listCodeEtat = array_column(
                (new EtatStat($this->pdo))->findAll([
                    'CODETAT' => $listCodeEtat,
                ]),
                'CODETAT'
            );
        }
        
        $post['listKpi'] = array_filter(array_map(
            function ($kpi) use ($listCodeEtat) {
                if (! in_array($kpi['CODE_ETAT'], $listCodeEtat)) {
                    LogSysteme::prefixErrorLog((string)(new \Exception('Invalid code etat "'.$kpi['CODE_ETAT'].'"')));
                    return null;
                }
                return $kpi;
            },
            $post['listKpi']
        ));

        //___________________
        // Validation

        foreach ($post['listKpi'] as $kpi) {
            // TODO : merge query in createKpiForm
            $form = $this->createKpiFormEditor($kpi['CODE_ETAT']);

            foreach ($form as $input) {
                $validateCallback = $input['validate'];
                $validateCallback(
                    $validator,
                    $kpi['mapFiltre'][ $input['Etatfiltre']['CODFILTRE'] ],
                    $post
                );
            }
        }
        if (! $validator->isValid()) {
            return new Response(400, [], $validator->getError());
        }

        //___________________
        
        $repo = new etatTableauDeBord($this->pdo);

        // Delete all then add all
        //$this->pdo->beginTransaction();

        $repo->reset($_SESSION['Session_Login']);
        $repo->multiInsertKpiItem(
            $_SESSION['Session_Login'],
            $post['listKpi']
        );

        //$this->pdo->commit();

        //___________________

        return new Response();
    }


    /**
     * @return Response|string
     */
    public function renderKpiInputAction()
    {
        $kpiId = $this->request->getAttribute('kpiId');
        $uid = $this->request->getAttribute('uid');
        $post = $this->request->getParsedBody();

        //___________________
        // Validation

        if ((new Periodes($this->pdo))->find($post['PERIODES']) == null) {
            throw new \Exception('Invalid periode "'.$post['PERIODES'].'"');
        }

        $validator = $this->createValidator();

        $form = $this->createKpiFormEditor($kpiId);

        foreach ($form as $input) {
            $validateCallback = $input['validate'];
            $validateCallback(
                $validator,
                $post[ $input['Etatfiltre']['CODFILTRE'] ],
                $post
            );
        }

        if (! $validator->isValid()) {
            return new Response(400, [], $validator->getError());
        }

        //___________________
        
        $listFiltreType = (new Etatfiltre($this->pdo))->findAll([
            'CODETAT' => $kpiId,
        ]);
        return $this->renderer->render('@Utilisateur/Dashboard/dashboard_kpiInput', [
            'uid' => $uid,
            'kpiId' => $kpiId,
            'listFiltre' => array_map(function ($filtreType) use ($post) {
                return [
                    'CODFILTRE' => $filtreType['CODFILTRE'],
                    'VALFILTRE' => $post[ $filtreType['CODFILTRE'] ] ?? '',
                ];
            }, $listFiltreType),
            // 'chart' => Highcharts::generate([
            //     'titre' => $kpiType['DESCRIPT'] . ' - ' . ($post['annee'] ?? date('Y')),
            //     'Fourchette' => [0, $data[1]['value']],
            //     'value' => $data[0]['value'],
            //     'legend' => 'TODO',
            //     'type' => 'solidgauge',
            // ], $this->pdo, $trad),
            'chartContent' => $this->getWsdlChartContent($kpiId, $post),
        ]);
    }

//_____________________________________________________________________________
// Sub-routine


    /**
     * @param array<mixed> $post
     */
    private function getWsdlChartContent(string $code_etat, array $post) :string
    {
        $res = file_get_contents(
            (new ParseBase1())->getRep()->tmp
            . $this->getWsdlChartFilename($code_etat, $post)
        );
        if ($res === false) {
            LogSysteme::prefixErrorLog((string)(new \Exception('!!!')));
            return 'Server error';
        }
        return $res;
    }

    /**
     * @param array<mixed> $post
     */
    private function getWsdlChartFilename(string $code_etat, array $post) :string
    {
        // Liste filtre by WSDL
        $xmlResult = new \Modules\EtatStatistiques\WebService\Statistique();
        
        // grace à notre retour wsdl ci-dessus on va alimenter un autre wsdl pour récupérer l'url
        $liste_etat_std_hc = $xmlResult->wsdlListeEtat_HC($code_etat, $post);

        // parcour du wsdl de retour pour récuprer l'url est afficher le graphe.
        /** @var \SimpleXMLElement $xml */
        $xml = simplexml_load_string($liste_etat_std_hc->responseData, "SimpleXMLElement", LIBXML_NOCDATA);
        /** @var \stdClass */
        $payload = Utils::jsonDecode(Utils::jsonEncode($xml));
        if (!is_string($payload->NomFichier)) {
            throw new \Exception('Invalid response '.var_export($xml, true));
        }
        return $payload->NomFichier;
    }

    /**
     * @param array<mixed>|null $post
     * @return array<array<mixed>> Array of KpiInput
     */
    private function createKpiFormEditor(string $code_etat, ?array $post = null) :array
    {
        // Filter PERIODES input is replaced by default value
        // since it will be overrided by a <select> at the top of the screen
        return array_filter(
            $this->createKpiForm($code_etat, $post),
            function ($input) {
                return $input['name'] != 'PERIODES';
            }
        );
    }

    /**
     * @param array<mixed>|null $post
     * @return array<array<mixed>> Array of KpiInput
     */
    private function createKpiForm(string $code_etat, ?array $post = null) :array
    {
        $listKpiFiltre = (new Etatfiltre($this->pdo))->findAll([
            'CODETAT' => $code_etat,
        ]);
        foreach ($listKpiFiltre as &$kpiFiltre) {
            $kpiFiltre['MULTIPLE'] = Sql::toBool($kpiFiltre['MULTIPLE']);
        }


        $form = [];

        // $listFiltreCode = array_column($listKpiFiltre, 'CODFILTRE');

        // if (! in_array('PERIODES', $listFiltreCode)) {
        //     $form[] = $this->createKpiInput(['CODFILTRE' => 'PERIODES']);
        // }
        
        // if (! in_array('SOCIETE', $listFiltreCode)) {
        //     $form[] = $this->createKpiInput([
        //         'CODFILTRE' => 'SOCIETE',
        //         'isMandatory' => true,
        //     ]);
        // }

        foreach ($listKpiFiltre as $filtre) {
            $form[] = $this->createKpiInput($filtre, $post[ $filtre['CODFILTRE'] ] ?? '');
        }

        return $form;
    }

    /**
     * @param array<mixed> $filtre Entity Etatfiltre
     * @param mixed $value
     * @return array<mixed> inputAdvance structure
     */
    private function createKpiInput(array $filtre, $value) :array
    {
        $trad = $this->getTranslationService();
        $filtreId = $filtre['CODFILTRE'];
        $code_etat = $filtre['CODETAT'];

        $paramtr = new Parametre($this->pdo);
        $entity = $paramtr->keyPathListe($filtre['CODFILTRE'], 'entity');
        $titre = $paramtr->keyPathListeTitre($filtre['CODFILTRE'], $trad);

        if ($filtre['MULTIPLE'] ?? false) {
            return [
                '_type' => 'ZOOM',
    
                'titre' => $titre,
                'name' => $filtreId,
                'pahtZoom' => $this->router->generateUri('GlobalApplication.MultiSelect.afficher'),
                'paramZoom' => [
                    'titre' => $titre,
                    'entity' => $entity,
                    'separateur' => '|',
                    'CODFILTRE' => $filtre['CODFILTRE'],
                    'listeValue' => $this->listFiltreOption($filtre) ?? '',
                    'codEtat' => $code_etat,
                ],
                'option' => 'desactiveSaisie',
                'entity' => $entity,
                'value' => $value,
                
                // TODO : simplify zoom advance
                'titleZoom' => $titre,
                'pathConvert' => $this->router->generateUri('Ajax.outil.convertLibelle'),
                'convertLibelle' => 'convertLibelleGlobal',
                // 'pathValidator' => $this->router->generateUri('Ajax.validator.zoom'),
                // 'paramsValidator' => json_encode([
                //     'entity' => $entity,
                //     'nomChamp' => $titre,
                // ]),

                'Etatfiltre' => $filtre,
                'validate' => function (Validator $validator, &$value, array $post) use ($filtre) {
                    $parameter = new Parametre($this->pdo);
                    
                    $value = empty($value) ? [] : explode('|', $value);
                    
                    foreach ($value as $subvalue) {
                        $validator->zoom(
                            $parameter->keyPathliste($filtre['CODFILTRE'], 'entity'),
                            $subvalue,
                            $parameter->keyPathListeTitre($filtre['CODFILTRE'], $validator->getTrad()),
                            $this->pdo,
                            true
                        );
                    }
                    // TODO : check length limit ?
                }
                   
            ];
        } else {
            switch ($filtreId) {
                case 'CENTRE_R':
                    $paramZoom = ['typeCentre' => 'LIVRAISON'];
                    break;
                case 'CENTRE_E':
                    $paramZoom = ['typeCentre' => 'EMISSION'];
                    break;
                case 'CENTRE_F':
                    $paramZoom = ['typeCentre' => 'FACTURAT'];
                    break;
                default:
                    $paramZoom = ['userCode' => $code_etat];
            }

            $isObligatoire = ($filtreId == 'PERIODES' || ($filtre['isMandatory'] ?? false));
            return [
                '_type' => 'ZOOMADVANCE',
    
                'titre' => $titre,
                'name' => $filtreId,
                'pahtZoom' => $this->router->generateUri(
                    $paramtr->keyPathListe($filtreId, 'path'),
                    $paramZoom
                ),
                'entity' => $entity,
                'value' => $value,
                'obligatoire' => $isObligatoire,
    
                // TODO : simplify zoom advance
                'titleZoom' => $titre,
                'pathConvert' => $this->router->generateUri('Ajax.outil.convertLibelle'),
                'convertLibelle' => 'convertLibelleGlobal',
                'pathValidator' => $this->router->generateUri('Ajax.validator.zoom'),
                'paramsValidator' => json_encode([
                    'entity' => $entity,
                    'nomChamp' => $titre,
                ]),

                'Etatfiltre' => $filtre,
                'validate' => function (Validator $validator, $value, array $post) use ($filtre, $isObligatoire) {
                    $parameter = new Parametre($this->pdo);
                    
                    $validator->zoom(
                        $parameter->keyPathliste($filtre['CODFILTRE'], 'entity'),
                        $value,
                        $parameter->keyPathListeTitre($filtre['CODFILTRE'], $validator->getTrad()),
                        $this->pdo,
                        ! $isObligatoire
                    );
                }
            ];
        }
    }


    /**
     * @param array<mixed> $filtre Entity Etatfiltre
     * @return array<array<mixed>>|null
     */
    private function listFiltreOption(array $filtre) :?array
    {
        $liste = new \Modules\Ajax\Repository\Listes($this->pdo);
        switch ($filtre['CODFILTRE']) {
            case 'CENTRE_R':
                return $liste->centreByType('LIVRAISON', [], null, true);
            case 'CENTRE_E':
                return $liste->centreByType('EMISSION', [], null, true);
            case 'CENTRE_F':
                return $liste->centreByType('FACTURAT', [], null, true);
            case 'ACHETEUR':
                return $liste->acheteur([]);
        }
        return null;
    }


    /**
     * @return array<mixed>
     */
    private function getKpiType(string $id) :array
    {
        $trad = $this->getTranslationService();
        switch ($id) {
            case 'KPI_CDE_ST':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_CDE_TD':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_CDE_TA':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_DA_TD':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_FOU_AC':
                // Highcharts::generate([
                //     'titre' => $trad->t('Nombre de fournisseurs actifs') . ' - ' . ($post['annee'] ?? date('Y')),
                //     'Fourchette' => [0, $nbrFournissActif[1]['value']],
                //     'value' => $nbrFournissActif[0]['value'],
                //     'legend' => $trad->t('Fournisseurs'),
                //     'type' => 'solidgauge',
                // ], $this->pdo, $trad);
                return [
                    'type' => 'solidgauge',
                    'legend' => $trad->t('Fournisseur'),
                ];
            case 'KPI_MNT_AC':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_CDE_MT':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_FA_CPT':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_FA_SOC':
                return [
                    'type' => 'wsdl',
                ];
            case 'KPI_DSIG':
                return [
                    'type' => 'wsdl',
                ];
        }
        throw new \Exception('invalid id "'.$id.'"');
    }
}
