<?php
namespace Modules\Fournisseur\Controller;

use API\Partenaire\IDataHinter;
use API\Partenaire\IEntitySearch;
use Entity\Model\Alias\ParamFourniss;
use Entity\Model\Fourniss;
use GuzzleHttp\Psr7\Response;
use Helpers\Ariane\Ariane;
use Helpers\Log\LogSysteme;
use Helpers\Outil\Roles;
use Helpers\Outil\Sql;
use Helpers\Session\Session;
use Helpers\Trad\Trad;
use Modules\Fournisseur\Service\CreateEditService;
use Modules\Fournisseur\WebService\Fournisseur;
use Skeleton\Controller\Controller;

class SearchImportFournisseurController extends Controller
{

    /**
     * @return Response|string
     */
    public function indexAction()
    {
        $modeSimplifier = $this->request->getAttribute('simplifier_mode');

        $service = $this->getPartenaireService();

        // Case : no config -> skip
        $config = $service->getCurrentMapping();
        if (empty($config->source)) {
            return $modeSimplifier !== null ?
                $this->redirect302('Fournisseur.CreationFournisseurSimplifier.nouveauFournisseur') :
                $this->redirect302('Fournisseur.CreationFournisseur.nouveauFournisseur');
        }
        
        $this->setupSession($modeSimplifier !== null);

        $trad = $this->getTranslationService();
        
        $paravrac = new ParamFourniss($this->pdo);

        Ariane::generate(1, $trad->t('Recherche via enrichisseur de données'));

        /** @var IEntitySearch */
        $partn = $service->getByCode($config->source);

        return $this->renderer->render('@Fournisseur/SearchImport/searchImport', [
            'hasFournissTypeChoice' => $this->hasFournissTypeChoice(),
            'paysDefault' => $paravrac->getPaysInstall(),
            'mapTaxeConfig' => $paravrac->getTaxeFieldMap(),
            'simplifierMode' => $modeSimplifier,
            // Case : mapping uses a field which require a call to companyInfo
            'needDetail' => $partn != null ?
                $partn->needDetail(Fourniss::class, $config->mapping['FOURNISS']) :
                false,
        ]);
    }


    public function searchAction() :Response
    {
        $post = $this->request->getParsedBody();
        $trad = $this->getTranslationService();
        $paravrac = new ParamFourniss($this->pdo);

        $validator = $this->createValidator();
        
        // At least one search field must be given
        $listValue = array_filter(array_map(
            function ($field) use ($post) {
                return $post[ $field ];
            },
            [
                'RS', 'CPOSTAL', 'VILLE',
                'NO_SIRET', 'TAXE2', 'TAXE3', 'TAXE4',
                'NO_TVA_IC', 'NO_DUNS', /* List of all inputs except CODE_PAYS */
            ]
        ));
        if (empty($listValue)) {
            $validator->setError($trad->t('Veuillez renseigner au moins un des champs.'));
        }

        // TODO : simplify
        // Validatoion : Siret uniq
        $warning = (object) []; // Force object in order to prevent ambiguity during json encoding
        $ctrlUniq = $paravrac->getSiretControlUniq(Sql::toBool($post['PROSPECT']));
        if (! empty($post['NO_SIRET'])
            && $post['CODE_PAYS'] == 'FR'
            && ! empty($ctrlUniq)
        ) {
            $duplicate = (new Fourniss($this->pdo))->find(
                ['NO_SIRET' => $post['NO_SIRET'], 'CODE_PAYS' => 'FR'],
                ['CODE','RS']
            );
            if (! empty($duplicate)) {
                if ($ctrlUniq == 'B') {
                    $validator->setError($trad->t('Un fournisseur avec le même SIRET existe déjà, il n’est pas possible de créer de doublon.'));
                } elseif ($ctrlUniq == 'N') {
                    $warning->NO_SIRET = [
                        'type' => 'duplicate',
                        'info' => $duplicate,
                        'link' => $this->router->generateUri(
                            'Fournisseur.Fournisseur.index',
                            ['id' => $duplicate['CODE']]
                        ),
                    ];
                }
            }
        }
        
        // Control unicité (hors France)
        $config = $paravrac->getTaxeField($post['CODE_PAYS']);
        if ($paravrac->getFlag('PARAMFOU', 'CTL_UNICITE_ACTIF')
            && $post['CODE_PAYS'] != 'FR'
        ) {
            $ctrlUniq =
                $paravrac->getFlag('PARAMFOU', 'CTL_UNICITE_ACTIF_NONBLOQUANT')
                ? 'N' /* Non-bloquant */ : 'B' /* Bloquant */;
            foreach (['NO_SIRET', 'TAXE2', 'TAXE3', 'TAXE4'] as $taxeField) {
                if (empty($post[ $taxeField ])) {
                    continue;
                }
                $duplicate = (new Fourniss($this->pdo))->find(
                    [
                        $taxeField => $post[ $taxeField ],
                        'CODE_PAYS' => $post['CODE_PAYS']
                    ],
                    ['CODE','RS']
                );
                if (! empty($duplicate)) {
                    if ($ctrlUniq == 'B') {
                        $validator->setError(
                            Trad::strBuild(
                                $trad->t('Un fournisseur avec le même @1@ existe déjà, il n’est pas possible de créer de doublon.'),
                                $config[ $taxeField ]->label
                            )
                        );
                    } else /*if ($ctrlUniq == 'N')*/ {
                        $warning->{ $taxeField } = [
                            'type' => 'duplicate',
                            'info' => $duplicate,
                            'link' => $this->router->generateUri(
                                'Fournisseur.Fournisseur.index',
                                ['id' => $duplicate['CODE']]
                            ),
                        ];
                    }
                }
            }
        }

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

        return $this->createJsonResponse([
            'warning' => $warning,
            'search' => $this->getListResult($post),
            'country_code' => $post['CODE_PAYS'],
        ]);
    }

    /**
     * @param array<mixed> $post
     * @return array{list:array<mixed>,count:?int,hasMore?:bool}
     */
    private function getListResult(array $post)
    {
        $service = $this->getPartenaireService();
        $config = $service->getCurrentMapping();
        if (empty($config->source)) {
            return ['list' => [], 'count' => null];
        }

        /** @var IEntitySearch */
        $partn = $service->getByCode($config->source); // TODO : handle multiple ?
        if ($partn == null) {
            return ['list' => [], 'count' => null];
        }

        //________

        $listResult =
            $partn->entitySearch(Fourniss::class, $post)
            ?? ['list' => [], 'count' => null];

        //_________
        // Apply uniq rules warning/error

        $paravrac = new ParamFourniss($this->pdo);
        $ctrlSiretUniq = $paravrac->getSiretControlUniq(Sql::toBool($post['PROSPECT']));

        if (! empty($ctrlSiretUniq) && $post['CODE_PAYS'] == 'FR') {
            $this->loadDuplicate(
                'FR',
                'NO_SIRET',
                $listResult['list'],
                $ctrlSiretUniq
            );
        }

        if ($paravrac->getFlag('PARAMFOU', 'CTL_UNICITE_ACTIF')
            && $post['CODE_PAYS'] != 'FR'
        ) {
            $ctrlUniq =
                $paravrac->getFlag('PARAMFOU', 'CTL_UNICITE_ACTIF_NONBLOQUANT')
                ? 'N' /* Non-bloquant */ : 'B' /* Bloquant */;
            foreach (['NO_SIRET', 'TAXE2', 'TAXE3', 'TAXE4'] as $taxeField) {
                $this->loadDuplicate(
                    $post['CODE_PAYS'],
                    $taxeField,
                    $listResult['list'],
                    $ctrlUniq
                );
            }
        }

        //_________

        return $listResult;
    }

    /**
     * @param array<mixed> $listFour
     */
    private function loadDuplicate(string $pays, string $taxeField, array &$listFour, string $ctrlUniq) :void
    {
        $listTaxeId = array_filter(array_unique(array_column(
            $listFour,
            $taxeField
        )));

        if (empty($listTaxeId)) {
            return;
        }

        $duplicate = array_column(
            (new Fourniss($this->pdo))->findAll(
                [$taxeField => $listTaxeId, 'CODE_PAYS' => $pays],
                ['CODE','RS', $taxeField]
            ),
            null,
            $taxeField
        );
        foreach ($listFour as &$item) {
            // Case: has no siret OR has no duplicate
            if (empty($item[$taxeField])
                || !isset($duplicate[ $item[$taxeField] ])
            ) {
                continue;
            }
            
            $item[ '_error' ] = [
                'type' => 'DUPLICATE',
                'level' => ($ctrlUniq == 'B' ? 'error': 'warning'),
                'field' => $taxeField,
                'duplicate' => $duplicate[ $item[$taxeField] ],
            ];
        }
    }

    public function detailAction() :Response
    {
        $post = $this->request->getParsedBody();

        $service = $this->getPartenaireService();
        $config = $service->getCurrentMapping();
        if (empty($config->source)) {
            return $this->createJsonResponse([
                'entity' => (object)[],
            ]);
        }

        /** @var IEntitySearch */
        $partn = $service->getByCode($config->source);
        if ($partn == null) {
            LogSysteme::prefixErrorLog('Invalid entity');
            return $this->createJsonResponse([
                'entity' => (object)[],
            ]);
        }
        
        return $this->createJsonResponse([
            'entity' => $partn->getDetail(Fourniss::class, $post),
        ]);
    }

    
    // TODO : remove ?
    public function formAutocompleteAction() :Response
    {
        $post = $this->request->getParsedBody();

        $service = $this->getPartenaireService();
        $listPartn = $service->listWithInterface(IDataHinter::class);
        if (empty($listPartn)) {
            return $this->createJsonResponse([
                'suggest' => [],
            ]);
        }

        $partn = $listPartn[0]; // TODO : handle multiple

        return $this->createJsonResponse([
            'suggest' => $partn->suggest(Fourniss::class, $post['form_data'], $post['prompter']),
        ]);
    }

//______________________________________________________________________________
// Sub-routine

    private function hasFournissTypeChoice() :bool
    {
        return Roles::droitsUtilisateur($this->pdo, 'HA_PRO_CRE')
            && Roles::droitsUtilisateur($this->pdo, 'HA_FOU_CRE');
    }

    private function setupSession(bool $isSimplifier) :void
    {
        (new Session('FournisseurSimplie'))->SuppresionSession();
        (new Session('Fournisseur'))->SuppresionSession();

        $session = new Session(
            $isSimplifier ? 'FournisseurSimplie' : 'Fournisseur',
            'Creation'
        );
        $session->setSession('modifFourniss', false);
        $session->setSession('searchImport', true);
        $fiche = new \SimpleXMLElement(
            (new Fournisseur())
                ->ficheFournisseur([
                    "Langue"      => $_SESSION['Session_Langue'],
                    "Login"       => $_SESSION['Session_Login'],
                    "no_ao"       => $_SESSION["Session_SocUsr"],
                    "codeFrs"     => '',
                    'codeDemande' => '',
                    'affDemande'  => 'FALSE',
                    'mode'        => 'V',
                ])
                ->responseData
        );
        $createService = new CreateEditService($this->pdo, $this->getTranslationService());
        $createService->initValueSession($session, $fiche);
        $createService->initValueSessionInteraction($session, $fiche);
    }
}
