<?php
namespace Modules\API\APIExterne\Controller;

use API\OnceForAll\OnceForAllPartenaire;
use API\Partenaire\Exception\WsInvalidResponse;
use Entity\Model\Contfour;
use Entity\Model\Country;
use Entity\Model\Docatt;
use Entity\Model\FourEve;
use Entity\Model\Fourniss;
use GuzzleHttp\Psr7\Response;
use Helpers\Log\LogSysteme;
use Helpers\Outil\ZoomHelper;
use Helpers\Trad\Trad;
use Helpers\Validator\FormValidator;
use Modules\API\APIExterne\Repository\Partenaire;
use Modules\Fournisseur\Repository\FourEventRepo;
use Skeleton\Controller\Controller;

class OnceForAllController extends Controller
{

    private function getPartenaire() :OnceForAllPartenaire
    {
        /** @phpstan-ignore-next-line */
        return $this->getPartenaireService()->getByCode('OFA');
    }

    public function popupFormInviteAction() :string
    {
        $fournissId = $this->request->getAttribute('fournissId');

        $fourniss = (new Fourniss($this->pdo))->find($fournissId);
        $country = (new Country($this->pdo))->find($fourniss['CODE_PAYS']);
        
        //________________
        // Validation du fournisseur

        $iso = Country::matchIso2($country);

        if ($iso == null) {
            $trad = $this->getTranslationService();
            return $this->renderer->render('@Ajax/Erreur/ErreurCreation', [
                'titrePopup' => $trad->t('Erreur de configuration'),
                'ErreurValid' => 'Invalid match iso2 for country "'.$country['CODE'].'"',
            ]);
        }
        $fourniss += ['Country' => $iso];

        $regnum = $this->getRegNumber($fourniss);

        if (empty($regnum)) {
            $trad = $this->getTranslationService();
            return $this->renderer->render('@Ajax/Erreur/ErreurCreation', [
                'titrePopup' => $trad->t('Erreur de configuration'),
                'ErreurValid' =>
                    [
                        'FR' => Trad::strBuild(
                            $trad->t('Le champ @1@ ne peut pas être vide.'),
                            'Siret'
                        ),
                        'IT' => Trad::strBuild(
                            $trad->t('Le champ @1@ ne peut pas être vide.'),
                            'Codice Fiscale'
                        ),
                    ][ $fourniss['Country']['iso2'] ]
                    ?? Trad::strBuild(
                        $trad->t('Le champ @1@ ne peut pas être vide.'),
                        'TVA intracommunautaire'
                    ),
            ]);
        }

        //________________
        
        // Since we are in the modal we use a custom table for contfour selection instead of a simple zoom
        return $this->renderer->render('@API/OnceForAll/popupFormInvite', [
            'fournissId' => $fournissId,
            'listContact' => (new Partenaire($this->pdo))->getListeContactOnceForAll($fournissId)
        ]);
    }

    public function inviteAction() :Response
    {
        $fournissId = $this->request->getAttribute('fournissId');
        $post = $this->request->getParsedBody();

        $fourniss = (new Fourniss($this->pdo))->find($fournissId);
        $country = (new Country($this->pdo))->find($fourniss['CODE_PAYS']);

        $iso = Country::matchIso2($country);

        // Fail safe : Assume API.OnceForAll.popupFormInvite already display an error message about it
        if ($iso == null) {
            return new Response(400);
        }

        $fourniss += ['Country' => $iso];
        $regnum = $this->getRegNumber($fourniss);
        // Fail safe : Assume API.OnceForAll.popupFormInvite already display an error message about it
        if (empty($regnum)) {
            return new Response(400);
        }

        //________________

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

        //________________

        $contact = (new Contfour($this->pdo))->find([
            'CODE_FOU' => $fournissId,
            'IND_FOU' => $post['contact'],
        ]);

        // Fail safe
        if (empty($contact['EMAIL']) || empty($contact['NOM']) || (empty($contact['TEL'])) && empty($contact['TELPORT'])) {
            throw new \Exception('');
        }

        list($firstName, $lastName) = explode(' ', $contact['NOM']);

        $trad = $this->getTranslationService();
        try {
            $this->getPartenaire()->inviteSubcontractor([
                'organisationName' => $fourniss['RS'],
                'country' => $iso['iso2'],
                'email' => $contact['EMAIL'],
                'lastName' => empty($lastName) ? substr($firstName, 0, 1) : $lastName,
                'firstName' => $firstName,
                'phoneNumber' => empty($contact['TEL'])
                    ? $contact['TELPORT']
                    : $contact['TEL'],
                'language' => $iso['iso2'] == 'fr' ? 'fr' : 'en', // TODO : match country and language
                'customMessage' => $trad->t('Nous vous invitons à vous enregistrer sur notre plateforme OnceForAll afin de faciliter la gestion de vos certificats'),
            ] + $regnum);
        } catch (WsInvalidResponse $e) {
            // Case : invite already sent
            if ($e->getResponse()->getStatusCode() == 409/* Conflict */) {
                $trad = $this->getTranslationService();
                return new Response(400, [], $trad->t('Une invitation pour ce fournisseur a déjà été créée'));
            }
            return new Response(400, [], $trad->t('L’invitation a échoué.'));
        }

        // Post processes
        (new FourEventRepo($this->pdo))->insertEvenement([
            'CODE' => $fournissId,
            'COMMENTAIRE' => 'Invitation OnceForAll envoyé a '.$contact['EMAIL'].'.',
            'EVENT' => 'PEV',
        ]);

        return new Response(200);
    }

    public function batchAction(string $numeroTraitement = '') :string
    {
        set_time_limit(0);

        $this->getPartenaire()->batch($numeroTraitement);
        return 'O';
    }

    public function docDownloadAction(): Response
    {
        $fournissId = $this->request->getAttribute('fournissId');
        $ordreId = $this->request->getAttribute('ordreId');
        $docAtt = (new Docatt($this->pdo))->find([
            'NO_DA' => 'FOURNISS',
            'COD_ENR' => $fournissId,
            'NO_ORDRE' => $ordreId,
        ]);

        $trad = $this->getTranslationService();

        $url = str_getcsv($docAtt['NOM_FIC'])[2] ?? null; // Get doc url
        if (empty($url)) {
            return new Response(404, [], $trad->t('Ce document n\'est pas disponible'));
        }

        try {
            $resp = $this->getPartenaire()->getWs()->getDocumentFile($url);
        } catch (WsInvalidResponse $e) {
            $resp = $e->getResponse();
            if ($resp != null && $resp->getStatusCode() != 404) {
                LogSysteme::prefixErrorLog('Invalid url "'.$url.'" : '. $resp->getStatusCode());
            }
            $trad = $this->getTranslationService();
            return new Response(404, [], $trad->t('Ce document n\'est pas disponible'));
        }

        return new Response(
            $resp->getStatusCode(),
            $resp->getHeaders(),
            $resp->getBody()
        );
    }

//_____________________________________________________________________________
// Sub-routine

    /**
     * @return array<\StdClass>
     */
    private function getFormInvite(string $fournissId)
    {
        $trad = $this->getTranslationService();
        return array_column([
            (object) ([
                'label' => $trad->t('Contact'),
                'name' => 'contact',
                'type' => 'ZOOM',
                'zoom_path' => 'Ajax.liste.contactFournisseur',
                'zoom_filter' => [
                    'CODE_FOU' => $fournissId,
                    'filter_func_CONTFOUR.EMAIL' => 'notempty',
                    'filter_func_CONTFOUR.NOM' => 'notempty',
                ],
                'inModal' => true,
            ])
        ], null, 'name');
    }
    /**
     * Depending on the country of both the inviteed and inviting organisations, the following rules apply:

    FR inviting FR: the invitation will be based on the registrationNumber (SIRET) only, which is then mandatory. vatIdentificationNumber cannot be used in this case (will return a 400 error)
    DE inviting DE: the invitation will be based on the vatIdentificationNumber only, which is then optional
    IT inviting IT: the invitation will be based on the registrationNumber (Codice Fiscale) only, which is then mandatory. vatIdentificationNumber cannot be used in this case (will return a 400 error)
    Any other cases: the invitation will be based on the vatIdentificationNumber only, which is then mandatory

     * @param array<mixed> $fourniss
     * @return array<mixed>
     */
    private function getRegNumber(array $fourniss) :array
    {
        if ($fourniss['Country']['iso2'] == 'FR'
            && ! empty($fourniss['NO_SIRET'])
        ) {
            return [
                'registrationNumber' => $fourniss['NO_SIRET'], // Assume Siret is taxe 1
            ];
        }
        
        $field = $this->getPartenaire()->getCodiceFiscaleField();
        if ($fourniss['Country']['iso2'] == 'IT'
            && ! empty($fourniss[ $field ])
        ) {
            return ['registrationNumber' => $fourniss[ $field ]];
        }

        if (! empty($fourniss['NO_TVA_IC'])) {
            return ['vatIdentificationNumber' => $fourniss['NO_TVA_IC']];
        }
        
        return [];
    }
}
