<?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\Outil\ArrayHelper;
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 = new FormValidator($this->pdo, $trad);
        $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']);
        $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')],
                ];
            }, [
                'ENSCOMM', 'RS', 'ADR', 'VILLE1', 'CPOSTAL',
                'TEL', 'FAX', 'EMAIL', 'SITEWEB',
                'NO_TVA_IC', 'NO_DUNS', 'TYP_TVA', 'ID_EXT',
                'DTEVALMIN', 'DTEVALMAX',
                //'FOUPPAL', // Groupement
            ]),
            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');
    }

    /**
     * @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

        // $s format : MAPPING.{field_name}
        switch (explode('|', $s)[1] ?? $s) {
            case 'ENSCOMM':
                return $trad->t('Enseigne commerciale');
            case 'RS':
                return $trad->t('Raison sociale');
            case 'ADR':
                return $trad->t('Adresse');
            case 'VILLE1':
                return $trad->t('Ville');
            case 'CPOSTAL':
                return $trad->t('Code postal');
            case 'TEL':
                return $trad->t('Téléphone');
            case 'FAX':
                return $trad->t('Fax');
            case 'EMAIL':
                return $trad->t('Email');
            case 'SITEWEB':
                return $trad->t('Site web');
            case 'NO_TVA_IC':
                return $trad->t('TVA Intracommunautaire');
            case 'NO_DUNS':
                return $trad->t('DUNS Number');
            case 'TYP_TVA':
                return $trad->t('Type de TVA');
            case 'ID_EXT':
                return $trad->t('Identifiant externe');
            case 'DTEVALMIN':
                return $trad->t('Date de validité début');
            case 'DTEVALMAX':
                return $trad->t('Date de validité fin');

            case 'CHIFF_AFF':
                return $trad->t('Chiffres d’affaires');
        }
        return $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;
    }
}
