<?php

namespace App\Service\Signature;

use App\Entity\Contrats;
use App\Entity\ContratsPayments;
use App\Entity\Devis;
use App\Entity\EtatLieux;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Vich\UploaderBundle\Storage\StorageInterface;

class Client
{
    private \Docuseal\Api $docuseal;
    private string $baseUrl;
    private string $logo;

    public function __construct(
        private readonly RequestStack $requestStack,
        private readonly UrlGeneratorInterface $urlGenerator,
        private readonly EntityManagerInterface $entityManager,
        private readonly KernelInterface $kernel,
        private readonly StorageInterface $storage,
        ?\Docuseal\Api $docuseal = null
    ) {
        // Configuration via les variables d'environnement
        $key = $_ENV['ESYSIGN_APIEY'] ?? '';
        $this->baseUrl = $_ENV['SIGN_URL'];

        // L'URL API est le point d'entrée pour le SDK Docuseal
        $apiUrl = rtrim("https://signature.esy-web.dev", '/') . '/api';
        $this->docuseal = $docuseal ?? new \Docuseal\Api($key, $apiUrl);
        $this->logo = $kernel->getProjectDir()."/sign_ludikevent.jpeg";
    }

    /**
     * Crée une soumission pour un Devis
     */
    public function createSubmissionDevis(Devis $devis): string
    {
        // Si aucune signature n'est lancée, on initialise la soumission
        if ($devis->getSignatureId() === null) {
            // URL où le client sera redirigé après signature
            $completedRedirectUrl =  $this->baseUrl . $this->urlGenerator->generate(
                    'app_sign_complete',
                    ['type' => 'devis', 'id' => $devis->getId()]
                );

            // Récupération du fichier via VichUploader (champ devisDocuSealFile)
            $relativeFileUrl = $this->storage->resolveUri($devis, 'devisDocuSealFile');
            $fileUrl =  $this->baseUrl . $relativeFileUrl;

            $submission = $this->docuseal->createSubmissionFromPdf([
                'name' => 'Devis N°' . $devis->getNum(), // Correction : getNum()
                'completed_redirect_url' => $completedRedirectUrl,
                'send_email' => true,
                'documents' => [
                    [
                        'name' => 'devis_' . $devis->getNum() . '.pdf', // Correction : getNum()
                        'file' => $fileUrl,
                    ],
                ],
                'submitters' => [
                    [
                        'role' => 'Ludikevent',
                        'email' => 'contact@ludikevent.fr',
                        'completed' => true,
                        'fields' => [
                            ['name'=>'Sign','default_value'=>$this->logoBase64()]
                        ]
                    ],
                    [
                        'role' => 'Client',
                        'email' => $devis->getCustomer()->getEmail(),
                        'name' => $devis->getCustomer()->getSurname() . ' ' . $devis->getCustomer()->getName(),
                        'fields' => [
                            ['name'=>'cgv','default_value'=>false],
                            ['name'=>'assurance','default_value'=>false],
                            ['name'=>'securite','default_value'=>false],
                            ['name'=>'arrhes','default_value'=>false],
                        ],
                        'metadata' => [
                            'id' => $devis->getId(),
                            'type' => 'devis'
                        ]
                    ],
                ],
            ]);


            // Stockage de l'ID submitter de Docuseal dans ton entité
            $devis->setSignatureId($submission['submitters'][1]['id']);
            $this->entityManager->persist($devis);

            $this->entityManager->flush();
        }

        return $this->getLinkSign($devis->getSignatureId());
    }

    /**
     * Retourne l'URL de signature publique pour le client
     */
    public function getLinkSign(?string $submitterId): string
    {
        if (!$submitterId) {
            throw new \InvalidArgumentException("ID Submitter absent.");
        }

        $submissionData = $this->docuseal->getSubmitter($submitterId);

        return rtrim("https://signature.esy-web.dev", '/') . "/s/" . $submissionData['slug'];
    }

    /**
     * Récupère l'état d'un signataire (pour vérifier si c'est signé)
     */
    public function getSubmiter(?string $submitterId): array
    {
        return $this->docuseal->getSubmitter($submitterId);
    }

    public function status(): bool
    {
        try {
            $this->docuseal->listTemplates();
            return true;
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * Récupère le fichier logo et le convertit en chaîne Base64
     * Utile pour l'intégration directe dans certains flux HTML ou API
     */
    private function logoBase64(): ?string
    {
        // Vérifie si le fichier existe pour éviter une erreur
        if (!file_exists($this->logo)) {
            return null;
        }

        // Lecture du contenu du fichier
        $binaryData = file_get_contents($this->logo);

        // Récupération de l'extension pour le type MIME (png, jpg, etc.)
        $extension = pathinfo($this->logo, PATHINFO_EXTENSION);

        // Encodage en Base64
        $base64 = base64_encode($binaryData);

        // Retourne le format complet data:image/...
        return 'data:image/' . $extension . ';base64,' . $base64;
    }

    public function getSubmition(mixed $submission_id)
    {
       return $this->docuseal->getSubmission($submission_id);
    }

    public function cancelSign(?string $getSignatureId)
    {
        $result = $this->docuseal->getSubmitter($getSignatureId);
        $this->docuseal->archiveSubmission($result['submission_id']);
    }


    public function createSubmissionContrat(Contrats $devis): string
    {
        // Si aucune signature n'est lancée, on initialise la soumission
        if ($devis->getSignID() === null) {

            // URL où le client sera redirigé après signature
            $completedRedirectUrl =  $this->baseUrl . $this->urlGenerator->generate(
                    'app_sign_complete',
                    ['type' => 'contrat', 'id' => $devis->getId()]
                );

            // Récupération du fichier via VichUploader (champ devisDocuSealFile)
            $relativeFileUrl = $this->storage->resolveUri($devis, 'devisDocuSealFile');
            $fileUrl =  $this->baseUrl . $relativeFileUrl;

            $submission = $this->docuseal->createSubmissionFromPdf([
                'name' => 'Contrat N°' . $devis->getNumReservation(), // Correction : getNum()
                'completed_redirect_url' => $completedRedirectUrl,
                'send_email' => true,
                'documents' => [
                    [
                        'name' => 'contrat_' . $devis->getNumReservation() . '.pdf', // Correction : getNum()
                        'file' => $fileUrl,
                    ],
                ],
                'submitters' => [
                    [
                        'role' => 'Ludikevent',
                        'email' => 'contact@ludikevent.fr',
                        'completed' => true,
                        'fields' => [
                            ['name'=>'Sign','default_value'=>$this->logoBase64()]
                        ]
                    ],
                    [
                        'role' => 'Client',
                        'email' => $devis->getCustomer()->getEmail(),
                        'name' => $devis->getCustomer()->getSurname() . ' ' . $devis->getCustomer()->getName(),
                        'fields' => [
                            ['name'=>'cgv','default_value'=>false],
                            ['name'=>'assurance','default_value'=>false],
                            ['name'=>'securite','default_value'=>false],
                            ['name'=>'arrhes','default_value'=>false],
                        ],
                        'metadata' => [
                            'id' => $devis->getId(),
                            'type' => 'contrat'
                        ]
                    ],
                ],
            ]);


            // Stockage de l'ID submitter de Docuseal dans ton entité
            $devis->setSignID($submission['submitters'][1]['id']);

            $this->entityManager->flush();
        }

        return $this->getLinkSign($devis->getSignID());
    }

    public function eventSign(object $contrat): array
    {
        $events = [];
        if ($contrat instanceof Contrats) {
            $signId = $contrat->getSignID();
            if (!$signId) return []; // Sécurité si pas d'ID de signature

            $submiter = $this->getSubmiter($signId);

            // Vérifier si submission_events existe pour éviter une erreur undefined index
            if (!isset($submiter['submission_events'])) return [];

            foreach ($submiter['submission_events'] as $event) {
                $label = match($event['event_type']) {
                    'view_form'     => "Contrat consulté",
                    'start_form'    => "Début de procédure",
                    'complete_form' => "Contrat signé",
                    'decline_form'  => "Signature refusée",
                    default         => null
                };

                if ($label) {
                    $events[] = [
                        'event_type' => $label,
                        'event_timestamp' => new \DateTimeImmutable($event['event_timestamp'])
                    ];
                }
            }
        }
        return $events;
    }

    public function signedData(Contrats $contrat) : string
    {
        $signId = $contrat->getSignID();
        if (!$signId) return []; // Sécurité si pas d'ID de signature

        $submiter = $this->getSubmiter($signId);
        return $submiter['uuid']; // numéro de signature;
    }

    public function autoSignConfirmedPayment(ContratsPayments $contratsPayments)
    {
        $relativeFileUrl = $this->storage->resolveUri($contratsPayments, 'paymentFile');
        $fileUrl = $this->baseUrl . $relativeFileUrl;

        $submission = $this->docuseal->createSubmissionFromPdf([
            'name' => 'Confirmation de paiement N°' . $contratsPayments->getPaymentId(),
            'send_email' => true,
            'documents' => [
                [
                    'name' => 'confirmation_paiement_' . $contratsPayments->getId() . '.pdf',
                    'file' => $fileUrl,
                ],
            ],
            'submitters' => [
                [
                    'role' => 'Ludikevent',
                    'email' => 'contact@ludikevent.fr',
                    'completed' => true,
                    'fields' => [
                        ['name' => 'Sign', 'default_value' => $this->logoBase64()]
                    ]
                ],
            ],
        ]);

        // --- SYSTÈME DE VÉRIFICATION DYNAMIQUE ---
        $maxAttempts = 10; // On essaie 10 fois maximum
        $attempts = 0;
        $documentUrl = null;

        while ($attempts < $maxAttempts) {
            $sub = $this->docuseal->getSubmission($submission['id']);

            // Vérification si le document et son URL sont prêts
            if (!empty($sub['documents'][0]['url'])) {
                $documentUrl = $sub['documents'][0]['url'];
                break; // On sort de la boucle dès que c'est prêt
            }

            $attempts++;
            usleep(500000); // Attend 0.5 seconde avant de réessayer (plus rapide que sleep(1))
        }

        if (!$documentUrl) {
            throw new \Exception("Docuseal n'a pas généré le document signé à temps pour le paiement " . $contratsPayments->getId());
        }

        return $documentUrl;
    }

    public function createSubmissionEtatLieux(EtatLieux $etatLieux): void
    {

        $contrat = $etatLieux->getContrat();
        $customer = $contrat->getCustomer();
        // Prestataire or Admin
        $prestataireEmail = 'contact@ludikevent.fr';
        if ($etatLieux->getPrestataire()) {
            $prestataireEmail = $etatLieux->getPrestataire()->getEmail();
        } elseif ($etatLieux->getAccount()) {
            $prestataireEmail = $etatLieux->getAccount()->getEmail();
        }

        // URL où on redirige après signature
        $completedRedirectUrl = $this->baseUrl . $this->urlGenerator->generate('etl_mission_signed_entry_state', ['id' => $contrat->getId()]);

        // Récupération du fichier PDF EDL (Non signé)
        $relativeFileUrl = $this->storage->resolveUri($etatLieux, 'etatLieuxUnsignFile');
        $fileUrl = $this->baseUrl . $relativeFileUrl;

        $submission = $this->docuseal->createSubmissionFromPdf([
            'name' => 'Etat des Lieux - Contrat #' . $contrat->getNumReservation(),
            'completed_redirect_url' => $completedRedirectUrl,
            'send_email' => true, // Envoi email aux deux parties
            'documents' => [
                [
                    'name' => 'edl_' . $contrat->getNumReservation() . '.pdf',
                    'file' => $fileUrl,
                ],
            ],
            'submitters' => [
                [
                    'role' => 'Ludikevent', // Prestataire
                    'email' => $prestataireEmail,
                ],
                [
                    'role' => 'Client',
                    'email' => $customer->getEmail(),
                    'name' => $customer->getSurname() . ' ' . $customer->getName(),
                ],
            ],
        ]);

        // Mapping des IDs
        foreach ($submission['submitters'] as $submitter) {
            if ($submitter['role'] === 'Ludikevent') {
                $etatLieux->setSignIdDelivery($submitter['id']);
            } elseif ($submitter['role'] === 'Client') {
                $etatLieux->setSignIdCustomer($submitter['id']);
            }
        }

        $this->entityManager->persist($etatLieux);
        $this->entityManager->flush();
    }

    public function getSigningUrl(EtatLieux $etatLieux, string $role): ?string
    {
        if($etatLieux->getStatus() == "edl_return_done"){
            $submitterId = match ($role) {
                'Ludikevent', 'Prestataire' => $etatLieux->getSignIdReturn(),
                'Client' => $etatLieux->getSignIdCustomerReturn(),
                default => null
            };
        } else {
            $submitterId = match ($role) {
                'Ludikevent', 'Prestataire' => $etatLieux->getSignIdDelivery(),
                'Client' => $etatLieux->getSignIdCustomer(),
                default => null
            };
        }

        if (!$submitterId) {
            return null;
        }

        return $this->getLinkSign($submitterId);
    }

    public function createSubmissionEtatLieuxSortant(?EtatLieux $etatLieux)
    {
        $contrat = $etatLieux->getContrat();
        $customer = $contrat->getCustomer();
        // Prestataire or Admin
        $prestataireEmail = 'contact@ludikevent.fr';
        if ($etatLieux->getPrestataire()) {
            $prestataireEmail = $etatLieux->getPrestataire()->getEmail();
        } elseif ($etatLieux->getAccount()) {
            $prestataireEmail = $etatLieux->getAccount()->getEmail();
        }

        // URL où on redirige après signature
        $completedRedirectUrl = $this->baseUrl . $this->urlGenerator->generate('etl_mission_signed_entry_state', ['id' => $contrat->getId()]);

        // Récupération du fichier PDF EDL (Non signé)
        $relativeFileUrl = $this->storage->resolveUri($etatLieux, 'etatLieuxUnsignReturnFile');
        $fileUrl = $this->baseUrl . $relativeFileUrl;

        $submission = $this->docuseal->createSubmissionFromPdf([
            'name' => 'Etat des Lieux - Contrat #' . $contrat->getNumReservation(),
            'completed_redirect_url' => $completedRedirectUrl,
            'send_email' => true, // Envoi email aux deux parties
            'documents' => [
                [
                    'name' => 'edl_' . $contrat->getNumReservation() . '.pdf',
                    'file' => $fileUrl,
                ],
            ],
            'submitters' => [
                [
                    'role' => 'Ludikevent', // Prestataire
                    'email' => $prestataireEmail,
                ],
                [
                    'role' => 'Client',
                    'email' => $customer->getEmail(),
                    'name' => $customer->getSurname() . ' ' . $customer->getName(),
                ],
            ],
        ]);

        // Mapping des IDs
        foreach ($submission['submitters'] as $submitter) {
            if ($submitter['role'] === 'Ludikevent') {
                $etatLieux->setSignIdReturn($submitter['id']);
            } elseif ($submitter['role'] === 'Client') {
                $etatLieux->setSignIdCustomerReturn($submitter['id']);
            }
        }

        $this->entityManager->persist($etatLieux);
        $this->entityManager->flush();
    }
}
