<?php

namespace App\Controller\Admin;

use App\Entity\Contrat;
use App\Service\DocuSealService;
use App\Service\MailerService;
use App\Service\Pdf\ContratMigrationSiteconseilPdf;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Twig\Environment;

#[Route('/admin/contrats', name: 'app_admin_contrats_')]
#[IsGranted('ROLE_EMPLOYE')]
class ContratController extends AbstractController
{
    public function __construct(
        private EntityManagerInterface $em,
    ) {
    }

    #[Route('', name: 'index')]
    public function index(): Response
    {
        $contrats = $this->em->getRepository(Contrat::class)->findBy([], ['createdAt' => 'DESC']);

        return $this->render('admin/contrats/index.html.twig', [
            'contrats' => $contrats,
        ]);
    }

    #[Route('/create', name: 'create', methods: ['POST'])]
    public function create(Request $request, KernelInterface $kernel): Response
    {
        $email = trim($request->request->getString('email'));
        $raisonSociale = trim($request->request->getString('raisonSociale'));
        $type = $request->request->getString('type');

        if ('' === $email || '' === $raisonSociale || '' === $type) {
            $this->addFlash('error', 'Tous les champs sont requis.');

            return $this->redirectToRoute('app_admin_contrats_index');
        }

        if (!isset(Contrat::TYPE_LABELS[$type])) {
            $this->addFlash('error', 'Type de contrat invalide.');

            return $this->redirectToRoute('app_admin_contrats_index');
        }

        // Recuperer les services
        $serviceKeys = $request->request->all('service_key');
        $serviceQtys = $request->request->all('service_qty');
        $services = [];

        foreach ($serviceKeys as $i => $key) {
            if ('' !== $key && isset(Contrat::SERVICE_CATALOG[$key])) {
                $qty = (int) ($serviceQtys[$i] ?? 1);
                if ($qty > 0) {
                    $services[] = [
                        'service' => $key,
                        'quantity' => $qty,
                        'priceHt' => Contrat::SERVICE_CATALOG[$key]['price'],
                    ];
                }
            }
        }

        $contrat = new Contrat($email, $raisonSociale, $type);
        $contrat->setServices($services);
        $this->em->persist($contrat);
        $this->em->flush();

        // Generer le PDF selon le type
        $this->generateContratPdf($contrat, $kernel);

        $this->addFlash('success', 'Contrat '.$contrat->getReference().' cree avec PDF.');

        return $this->redirectToRoute('app_admin_contrats_show', ['id' => $contrat->getId()]);
    }

    #[Route('/{id}', name: 'show', requirements: ['id' => '\d+'])]
    public function show(int $id): Response
    {
        $contrat = $this->em->getRepository(Contrat::class)->find($id);
        if (null === $contrat) {
            throw $this->createNotFoundException('Contrat introuvable');
        }

        return $this->render('admin/contrats/show.html.twig', [
            'contrat' => $contrat,
        ]);
    }

    #[Route('/{id}/generate-pdf', name: 'generate_pdf', requirements: ['id' => '\d+'], methods: ['POST'])]
    public function generatePdf(int $id, KernelInterface $kernel): Response
    {
        $contrat = $this->em->getRepository(Contrat::class)->find($id);
        if (null === $contrat) {
            throw $this->createNotFoundException('Contrat introuvable');
        }

        $this->generateContratPdf($contrat, $kernel);
        $this->addFlash('success', 'PDF regenere.');

        return $this->redirectToRoute('app_admin_contrats_show', ['id' => $id]);
    }

    /**
     * Envoie le contrat pour signature DocuSeal (2 parties : Company auto-signe + Client signe).
     */
    #[Route('/{id}/send-signature', name: 'send_signature', requirements: ['id' => '\d+'], methods: ['POST'])]
    public function sendSignature(
        int $id,
        DocuSealService $docuSeal,
        MailerService $mailer,
        Environment $twig,
        UrlGeneratorInterface $urlGenerator,
        #[Autowire(env: 'DOCUSEAL_URL')] string $docuSealUrl = '',
        #[Autowire('%kernel.project_dir%')] string $projectDir = '',
    ): Response {
        $contrat = $this->em->getRepository(Contrat::class)->find($id);
        if (null === $contrat) {
            throw $this->createNotFoundException('Contrat introuvable');
        }

        if (null === $contrat->getPdfUnsigned()) {
            $this->addFlash('error', 'Le PDF doit etre genere avant l\'envoi.');

            return $this->redirectToRoute('app_admin_contrats_show', ['id' => $id]);
        }

        $pdfPath = $projectDir.'/public/uploads/contrats/'.$contrat->getPdfUnsigned();
        if (!file_exists($pdfPath)) {
            $this->addFlash('error', 'Fichier PDF introuvable.');

            return $this->redirectToRoute('app_admin_contrats_show', ['id' => $id]);
        }

        $signedRedirectUrl = $urlGenerator->generate('app_admin_contrats_show', [
            'id' => $contrat->getId(),
        ], UrlGeneratorInterface::ABSOLUTE_URL);

        try {
            $pdfBase64 = base64_encode(file_get_contents($pdfPath));

            $result = $docuSeal->getApi()->createSubmissionFromPdf([
                'name' => 'Contrat '.$contrat->getReference().' - '.$contrat->getRaisonSociale(),
                'send_email' => false,
                'flatten' => true,
                'documents' => [[
                    'name' => 'contrat-'.$contrat->getReference().'.pdf',
                    'file' => 'data:application/pdf;base64,'.$pdfBase64,
                ]],
                'submitters' => [
                    [
                        'email' => 'client@e-cosplay.fr',
                        'name' => 'Association E-Cosplay',
                        'role' => 'Company',
                        'completed' => true,
                        'send_email' => false,
                        'values' => ['Sign' => $docuSeal->getLogoBase64()],
                        'metadata' => ['doc_type' => 'contrat', 'contrat_id' => $contrat->getId()],
                    ],
                    [
                        'email' => $contrat->getEmail(),
                        'name' => $contrat->getRaisonSociale(),
                        'role' => 'First Party',
                        'send_email' => false,
                        'completed_redirect_url' => $signedRedirectUrl,
                        'metadata' => ['doc_type' => 'contrat', 'contrat_id' => $contrat->getId()],
                    ],
                ],
            ]);

            $submitterId = $result['submitters'][1]['id'] ?? ($result[1]['id'] ?? null);
            $companySubmitterId = $result['submitters'][0]['id'] ?? ($result[0]['id'] ?? null);

            if (null !== $submitterId) {
                $contrat->setSubmissionId((string) $submitterId);
                $contrat->setSubmitterCompanyId(null !== $companySubmitterId ? (int) $companySubmitterId : null);
                $contrat->setSubmitterCustomerId((int) $submitterId);
                $contrat->setState(Contrat::STATE_SEND);
                $this->em->flush();

                // Envoyer email au client avec le lien
                $slug = $docuSeal->getSubmitterSlug($submitterId);
                $signUrl = null !== $slug ? rtrim($docuSealUrl, '/').'/s/'.$slug : null;

                $mailer->sendEmail(
                    $contrat->getEmail(),
                    'Contrat a signer - '.$contrat->getTypeLabel().' - '.$contrat->getReference(),
                    $twig->render('emails/contrat_signature.html.twig', [
                        'contrat' => $contrat,
                        'signUrl' => $signUrl,
                    ]),
                    null,
                    null,
                    false,
                );

                $this->addFlash('success', 'Contrat envoye pour signature a '.$contrat->getEmail().'.');
            } else {
                $this->addFlash('error', 'Erreur DocuSeal : aucun submitter retourne.');
            }
        } catch (\Throwable $e) {
            $this->addFlash('error', 'Erreur DocuSeal : '.$e->getMessage());
        }

        return $this->redirectToRoute('app_admin_contrats_show', ['id' => $id]);
    }

    #[Route('/{id}/cancel', name: 'cancel', requirements: ['id' => '\d+'], methods: ['POST'])]
    public function cancel(int $id): Response
    {
        $contrat = $this->em->getRepository(Contrat::class)->find($id);
        if (null === $contrat) {
            throw $this->createNotFoundException('Contrat introuvable');
        }

        $contrat->setState(Contrat::STATE_CANCELLED);
        $this->em->flush();

        $this->addFlash('success', 'Contrat annule.');

        return $this->redirectToRoute('app_admin_contrats_index');
    }

    private function generateContratPdf(Contrat $contrat, KernelInterface $kernel): void
    {
        $pdf = match ($contrat->getType()) {
            Contrat::TYPE_MIGRATION_SITECONSEIL => new ContratMigrationSiteconseilPdf($kernel, $contrat),
            default => throw new \RuntimeException('Type de contrat non supporte : '.$contrat->getType()),
        };

        $pdf->generate();

        $tmpPath = tempnam(sys_get_temp_dir(), 'contrat_').'.pdf';
        $pdf->Output('F', $tmpPath);

        $contrat->setPdfUnsignedFile(new UploadedFile(
            $tmpPath,
            'contrat-'.$contrat->getReference().'.pdf',
            'application/pdf',
            null,
            true,
        ));
        $contrat->setUpdatedAt(new \DateTimeImmutable());
        $this->em->flush();

        @unlink($tmpPath);
    }
}
