<?php
namespace Modules\EtatStatistiques\Controller;

use Entity\Model\ReqFiltresDon;
use Helpers\Form\FormBuilder;
use Helpers\Outil\Sql;
use Helpers\Pagination\PaginatorEtatStat;
use Helpers\QueryBuilder\EntityTool;
use Modules\EtatStatistiques\Outil\EtatStatOutil;
use Modules\EtatStatistiques\Repository\EtatStatDataRepo;
use Modules\EtatStatistiques\Repository\EtatStatTypeRepo;
use Skeleton\Controller\Controller;

class EtatStatDataVisuController extends Controller
{
    protected function getRepo() :EtatStatTypeRepo
    {
        return new EtatStatTypeRepo($this->getPdo());
    }

    protected function getDataRepo() :EtatStatDataRepo
    {
        return new EtatStatDataRepo($this->mustGetPdoOxaDw());
    }

//_____________________________________________________________________________
// Actions

    /**
     * @return string|\GuzzleHttp\Psr7\Response
     */
    public function detailAction()
    {
        $id = $this->request->getAttribute('id');
        $etatstat = (new EtatStatTypeRepo($this->pdo))->getEtatDetail($id);
        
        if (empty($etatstat)) {
            return $this->create404Response();
        }

        // Load FiltreUtil.ListChoix
        $etatstat['ListFilter'] = $this->getRepo()->loadListChoix($etatstat['ListFilter']);

        return
            $etatstat['TYPERES'] == 'T'/* Tableau */
                ? $this->detailTable($etatstat)
                : $this->detailGraph($etatstat);
    }


    /**
     * @param array<mixed> $etatstat
     */
    public function detailTable(array $etatstat) :string
    {
        $post = $this->request->getParsedBody();
        
        $data = $this->getDataRepo()->getData(
            $etatstat,
            ['paginator' => 50]
            + $this->request->getParsedBody()
        );
        
        return $this->renderer->render('@EtatStatistiques/Tableau/pageTableEtatStat', [
            'form_filter' => $this->filterToInput($etatstat['ListFilter']),
            'etatstat' => $etatstat,
            'post' => $post,
            'gestable' => $this->getGestable($etatstat, $data),
            'hasErrorSql' => $this->mustGetPdoOxaDw()->getErrorCount(),
        ]);
    }

    /**
     * @param array<mixed> $etatstat
     */
    private function detailGraph(array $etatstat) :string
    {
        $post = $this->request->getParsedBody();
        
        $listRow = $this->getDataRepo()->getData(
            $etatstat,
            [] // ['paginator' => 50]
            + $this->request->getParsedBody()
        );

        
        $mapColFormat = EtatStatDataRepo::getColDisplayFormat($etatstat, $listRow[0] ?? []);
        return $this->renderer->render('@EtatStatistiques/Tableau/pageGraphEtatStat', [
            'form_filter' => $this->filterToInput($etatstat['ListFilter']),
            'etatstat' => $etatstat,
            'post' => $post,
            'listRow' => array_map(function ($row) use ($mapColFormat) {
                return $this->formatRow($row, $mapColFormat);
            }, $listRow),
            'hasErrorSql' => $this->mustGetPdoOxaDw()->getErrorCount(),
        ]);
    }

//_____________________________________________________________________________
// Sub-routine

    /**
     * @param array<mixed> $row
     * @param array<mixed> $mapColFormat
     * @return array<mixed>
     */
    private function formatRow(array $row, array $mapColFormat)
    {
        $tmp = [];
        foreach ($row as $key => $value) {
            $tmp[$key] = EntityTool::formatTableFieldDisplay(
                $mapColFormat[ $key ],
                $value,
                $this->getTranslationService()
            );
        }
        return $tmp;
    }

    /**
     * @param array<mixed> $etatstat entity Etatstat
     * @param array<mixed> $data return from the custom query
     * @return \stdClass
     */
    private function getGestable(array $etatstat, array $data)
    {
        $mainQuery = $etatstat['Requete'];
        
        $firstRow = $data[0] ?? [];
        $trad = $this->getTranslationService();

        $mapColFormat = EtatStatDataRepo::getColDisplayFormat($etatstat, $firstRow);

        $mapColAlias = array_column($mainQuery['ListSelect'] ?? [], 'ELEM_ALIAS', 'ELEM_SQL');

        return (object) [
            'listCol' =>
                Sql::toBool($mainQuery['REQ_LIBRE'])
                ? array_filter(array_map(
                    function ($col) use ($mapColFormat) {
                        if (str_starts_with((string) $col, 'OxaCountPaginator')
                            || str_starts_with((string) $col, '_Rupture_')
                        ) {
                            return null;
                        }
                        return (object)([
                            'name' => $col,
                            'label' => $col,
                            'format' => $mapColFormat[ $col ]
                        ]);
                    },
                    array_keys($firstRow)
                ))
                : array_map(
                    function ($select) use ($mapColFormat) {
                        return (object)[
                            'name' => $select['ELEM_ALIAS'],
                            'label' => $select['ELEM_ALIAS'],
                            'format' => $mapColFormat[ $select['ELEM_ALIAS'] ],
                            // 'filter' => [
                            //     'type' => 'text',
                            //         // $select['RSEL_TYPE_DONNEE'] == 'A' 'N' 'D' ?  'text' / 'zoom' / integer
                            // ],
                        ];
                    },
                    $mainQuery['ListSelect'] ?? []
                ),
            'listRow' => $data,
            // TODO : Document listRupture
            // 'listRupture' => array_filter([
            //     $mainQuery['Rupture'] ? [
            //         'label' => $mainQuery['Rupture']['TEXTE_RUP'],
            //         'field' => '_Rupture_'.$mainQuery['Rupture']['NUM_ORD'].'_key',
            //         'labelTot' => $trad->t('Total'),
            //         'fieldTot' => '_Rupture_'.$mainQuery['Rupture']['NUM_ORD'].'_total1',// TODO allow multiple rupture total
            //     ] : null
            // ]),
            'listRupture' => array_filter([
                $mainQuery['Rupture'] ? [
                    // Use custom {% block rupture %}
                    'colLabelAlias' => $mapColAlias[
                        $mainQuery['Rupture']['NOM_CHP']
                    ],
                    'label' => $mainQuery['Rupture']['TEXTE_RUP'],
                    'targetField' => $mainQuery['Rupture']['TEXTE_RUP'],
                    'field' => '_Rupture_'.$mainQuery['Rupture']['NUM_ORD'].'_key',
                    'mapTot' => array_column(
                        $mainQuery['Rupture']['ListRuptureTot'],
                        'NUM_ORD',
                        'NOM_CHP'
                    )
                ] : null
            ]),
            'pagination' => PaginatorEtatStat::$lastPagination->getInfoPagination()
                + ['path' => $this->router->generateUri(
                    $this->router->getNameRoute(),
                    $this->request->getAttributes()
                )]
        ];
    }

    /**
     * @param array<array<mixed>> $listFilter list of entity ReqFiltres
     * @throws \Exception
     * @return array<\stdClass>
     */
    private function filterToInput(array $listFilter)
    {
        $builder = new FormBuilder();
        foreach ($listFilter as $filter) {
            $code = ReqFiltresDon::getInputId($filter);
            switch ($filter['TYPE_FILTRE']) {
                case 'USER':
                    if ($filter['FENT_TYPE_AFFICHAGE'] == 'L') {
                        $builder->addSelect(
                            $code,
                            ['' => '']
                            + array_column(
                                $filter['ListChoix'] ?? [],
                                'FLIS_LIBELLE',
                                'FLIS_VALEUR'
                            ),
                            ['label' => $filter['LIB_FILTRE']]
                        );
                        break;
                    }
                     // Assume $filter['FENT_TYPE_AFFICHAGE'] == 'R'
                    // TODO : EtatStatistique.ajaxListe.acheteurEtatStat does not work
                        // 'entity' => Hastutil::class,
                        // 'zoom_path' => 'EtatStatistique.ajaxListe.acheteurEtatStat',
                        // 'zoom_path_param' => [// TODO : implements FormExtention
                        //     'filtre' => $filter['CODE_FILTRE'],
                        // ],
                        // 'zoom_filter' => ['CODE_FILTRE' => $filter['CODE_FILTRE']]
                        
                    $builder->addText($code, 3000, ['label' => $filter['LIB_FILTRE']]);
                    break;
                case 'STD':
                case 'CS':
                    if ($filter['TYPE_DON_FILTRE'] == 'D') {
                        $builder->addDate($code, ['label' => $filter['LIB_FILTRE']]);
                    } elseif ($filter['TYPE_DON_FILTRE'] == 'N') {
                        if ($filter['PD_LONG'] == '0') {
                            $builder->addInteger($code, ['label' => $filter['LIB_FILTRE']]);
                        } else {
                            $builder->addFloat(
                                $code,
                                $filter['PE_LONG'] . '.' . $filter['PD_LONG'],
                                ['label' => $filter['LIB_FILTRE']]
                            );
                        }
                    } else { // Assume 'A' Alpha
                        if ($filter['TYPE_FILTRE'] == 'STD') {
                            $info = EtatStatOutil::getFilterInfo($filter['CODE_FILTRE']);
                            if ($info === null) {
                                throw new \Exception('Invalid code "'.$filter['CODE_FILTRE'].'"');
                            }
                            $builder->addZoom($code, $info['path'], [
                                'label' => $filter['LIB_FILTRE'],
                                'zoom_path_param' => $info['path_param'] ?? [],
                            ]);
                            break;
                        }

                        $builder->addText($code, intval($filter['ALP_LONG']), [
                            'label' => $filter['LIB_FILTRE'],
                        ]);
                    }
                    break;
                case 'LIBRE':
                    if ($filter['TYPE_DON_FILTRE'] == 'D') {
                        $builder->addDate($code . '_START', [
                            'label' =>
                                $filter['LIB_FILTRE']
                                . ' '
                                . $this->getTranslationService()->t('compris entre')
                        ]);
                        $builder->addDate($code . '_END', [
                            'label' => $this->getTranslationService()->t('et')
                        ]);
                    } else {
                        $builder->addText($code, 3000, [
                            'label' => $filter['LIB_FILTRE'],
                        ]);
                    }
                    break;
                default:
                    throw new \Exception('Invalid type "'.$filter['TYPE_FILTRE'].'"');
            }
        }
        return $builder->build();
    }
}
