<?php

namespace Modules\Parametrage\API\Controller;

use API\Partenaire\IEntitySearch;
use Entity\Model\Alias\ParamFourniss;
use Entity\Model\Country;
use Entity\Model\Fourniss;
use GuzzleHttp\Psr7\Response;
use Helpers\ChampsSupplementaire\ChampSupp;
use Helpers\Outil\ArrayHelper;
use Helpers\Parametres\Constante;
use Helpers\Validator\FormValidator;
use Skeleton\Controller\Controller;

class ParametrageApiExtController extends Controller
{
    /**
     * @return \GuzzleHttp\Psr7\Response|string
     * @throws \Exception
     */
    public function indexAction()
    {
        $trad = $this->getTranslationService();
        $service = $this->getPartenaireService();

        $listChoice = [];
        foreach ($service->listActifPartenaire() as $partenaire) {
            if (! ($partenaire instanceof IEntitySearch)) {
                continue;
            }
            $listChoice[ $partenaire->getCode() ] = $partenaire->getLabel();
        }

        $config = $service->getCurrentMapping();
        $config->mapping = $config->mapping['FOURNISS'];

        // Flatten taxe
        $config->mapping = ArrayHelper::flattenOnce($config->mapping, '|');

        $partn = null;
        if (! empty($config->source)) {
            $partn = $service->getByCode($config->source);
            if (! ($partn instanceof IEntitySearch)) {
                $partn = null;
            }
        }


        return $this->renderer->render('@ParamAPI/index', [
            'config' => $config,
            'listPartnChoice' =>
                ['' => $trad->t('Aucune')]
                + $listChoice,
        ] + ($partn != null ?
            $this->getFormRenderParam($partn) : []
        ));
    }

    public function formMappingAction() :string
    {
        $codePart = $this->request->getParsedBody()['partn'];
        $service = $this->getPartenaireService();
        
        $partn = $service->getByCode($codePart);
        if ($partn == null || !($partn instanceof IEntitySearch)) {
            return 'Not found';
        }
        return $this->renderer->render(
            '@ParamAPI/_form_mapping',
            $this->getFormRenderParam($partn)
        );
    }

    /**
     * @return array<mixed>
     */
    private function getFormRenderParam(?IEntitySearch $partn)
    {
        $paravrac = new ParamFourniss($this->pdo);
        $configTaxe = $paravrac->getTaxeFieldMap();
        unset($configTaxe['_default']);
        return [
            'defaultCountry' => $paravrac->getPaysInstall(),
            'configTaxe' => $configTaxe,
            'mapCountry' => array_column(
                (new Country($this->pdo))
                    ->findAll(['CODE_PAYS' => array_keys($configTaxe)]),
                null,
                'CODE_PAYS'
            ),
            'form' => $partn != null ?
                $this->getFormView($this->createFormMapping($partn)) :
                null,
        ];
    }

    public function updateMappingAction() :Response
    {
        $post = $this->request->getParsedBody();
        $trad = $this->getTranslationService();
        $service = $this->getPartenaireService();

        // Case : Set to "none"
        if (empty($post['ExtEntSrc'])) {
            $service->setExtEntSrc($post['ExtEntSrc'], []);
            return new Response(200);
        }
        
        $partn = $service->getByCode($post['ExtEntSrc']);
        if ($partn == null || !($partn instanceof IEntitySearch)) {
            return new Response(400, [], 'Invalid choice');
        }

        $validator = $this->createFormValidator();
        $form = $this->getFormView($this->createFormMapping($partn)); // Note : the view is required for RS validation

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

        $service->setExtEntSrc($post['ExtEntSrc'], $mapping);

        return new Response(200);
    }

//______________________________________________________________________________
// Sub-routine

    /**
     * @return array<\stdClass>
     */
    private function createFormMapping(IEntitySearch $partn) :array
    {
        $trad = $this->getTranslationService();
        $configTaxe = (new ParamFourniss($this->pdo))->getTaxeFieldMap();
        unset($configTaxe['_default']);

        

        // Champ sup
        $csSchema = array_filter(
            (new ChampSupp($this->getPdo()))->getSchema('FOURNISS'),
            fn($cs) => $cs['TYPE'] == 'ALPHA'
        );

        $choicesMapping = $partn->listMappingChoice(Fourniss::class, '', $trad);
        return array_column(array_merge(
            array_map(
                function ($field) use ($choicesMapping) {
                    return (object) [
                        'name' => $field,
                        'type' => 'SELECT',
                        'choices' => $choicesMapping,
                        'validator' => ['mandatory' => ($field == 'RS')],
                    ];
                },
                array_merge(
                    [
                        'ENSCOMM', 'RS', 'ADR', 'VILLE1', 'CPOSTAL',
                        'TEL', 'FAX', 'EMAIL', 'SITEWEB',
                        'NO_TVA_IC', 'NO_DUNS', 'TYP_TVA', 'ID_EXT',
                        'DTEVALMIN', 'DTEVALMAX',
                        //'FOUPPAL', // Groupement
                    ],
                    array_map(fn($cs) => 'cs|' . $cs['NUM_FIX'], $csSchema)
                )
            ),
            array_map(function ($field) use ($partn, $trad) {
                return (object) [
                    'name' => $field,
                    'type' => 'SELECT',
                    'choices' => $partn->listMappingChoice(Fourniss::class, $field, $trad),
                ];
            }, ['CHIFF_AFF']),
            array_map(function ($codePays) use ($choicesMapping) {
                return $this->createInputGroup(
                    'taxe|' . $codePays,
                    array_map(function (string $field) use ($choicesMapping) {
                        return (object) [
                            'name' =>  $field,
                            'type' => 'SELECT',
                            'choices' => $choicesMapping,
                        ];
                    }, ['NO_SIRET', 'TAXE2', 'TAXE3', 'TAXE4'])
                );
            }, array_keys($configTaxe))
        ), null, 'name');
    }

    /**
     * @todo : factorize with FormBuilder::addGroup
     * @param array<\stdClass> $listChild
     * @return \stdClass
     */
    private function createInputGroup(string $name, array $listChild)
    {
        return (object) [
            'type' => 'GROUP',
            'name' => $name,
            'listChild' => array_map(function ($input) use ($name) {
                $input->fullName = $name. '['.$input->name.']'; // TODO : handle multiple level
                return $input;
            }, $listChild),
        ];
    }

    private function getInputLabel(string $s) :string
    {
        $trad = $this->getTranslationService();
        // TODO : replace by Fourniss field label
        return match ($s) {
            'ENSCOMM' => $trad->t('Enseigne commerciale'),
            'RS' => $trad->t('Raison sociale'),
            'ADR' => $trad->t('Adresse'),
            'VILLE1' => $trad->t('Ville'),
            'CPOSTAL' => $trad->t('Code postal'),
            'TEL' => $trad->t('Téléphone'),
            'FAX' => $trad->t('Fax'),
            'EMAIL' => $trad->t('Email'),
            'SITEWEB' => $trad->t('Site web'),
            'NO_TVA_IC' => $trad->t('TVA Intracommunautaire'),
            'NO_DUNS' => $trad->t('DUNS Number'),
            'TYP_TVA' => $trad->t('Type de TVA'),
            'ID_EXT' => $trad->t('Identifiant externe'),
            'DTEVALMIN' => $trad->t('Date de validité début'),
            'DTEVALMAX' => $trad->t('Date de validité fin'),

            'CHIFF_AFF' => $trad->t('Chiffres d’affaires'),

            default => null,
        }
        ?? (str_starts_with($s, 'cs|')
            ? array_column(
                (new ChampSupp($this->getPdo()))->getSchema('FOURNISS'),
                null,
                'NUM_FIX'
            )[ explode('|', $s)[1] ?? '' ]['NOM'] ?? null
            : null
        )
        ?? $s;
    }

    /**
     * @param array<\stdClass> $form
     * @param ?\stdClass $parent input parent in the case of a GROUP
     * @return array<\stdClass>
     */
    private function getFormView(array $form, ?object $parent = null)
    {
        $mapConfigTaxe = (new ParamFourniss($this->pdo))->getTaxeFieldMap();
        foreach ($form as $input) {
            if ($input->type == 'GROUP') {
                $this->getFormView($input->listChild, $input);
            }
            if (in_array($input->name, ['NO_SIRET', 'TAXE2', 'TAXE3', 'TAXE4'])) {
                $codePays = explode('|', $parent->name)[1] ?? '';/// Parse "taxe|{CODE_PAYS}"
                $input->label = $mapConfigTaxe[ $codePays ][ $input->name ]->label;
                continue;
            }
            $input->label = $this->getInputLabel($input->name);
        }
        return $form;
    }
}
