<?php

declare(strict_types=1);

namespace App\Service\Whatsapp;

use App\Entity\Classe;
use App\Entity\Ecole;
use App\Entity\Etudiant;
use App\Entity\Inscription;
use App\Entity\Section;
use App\Service\Pdf\InscriptionPdfGenerator;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;

final class WhatsappNotificationService
{
    public function __construct(
        private readonly GreenApiClient $greenApi,
        private readonly EntityManagerInterface $entityManager,
        private readonly InscriptionPdfGenerator $pdfGenerator,
        private readonly LoggerInterface $logger,
        private readonly string $projectDir,
        private readonly string $publicBaseUrl = '',
    ) {
    }

    public function notifyInscriptionSubmitted(Inscription $inscription): void
    {
        $phone = $this->candidatePhone($inscription);
        if (!$phone) {
            return;
        }

        $schoolName = $this->schoolName($inscription);
        $message = "Assalamou aleykoum wa rahmatoullah wa barakatouh,\n\n"
            .sprintf("Votre demande d’inscription à *%s* a bien été enregistrée.\n\n", $schoolName)
            .sprintf("*Numéro de dossier :* %s\n", $inscription->getNumeroDossier() ?: '-')
            .sprintf("*Nom de l’apprenante :* %s\n", mb_strtoupper($inscription->getNomComplet(), 'UTF-8'))
            ."*Statut :* Demande reçue, en attente de traitement\n\n"
            ."Vous trouverez ci-joint votre *fiche provisoire d’inscription* au format PDF.\n\n"
            ."Merci de conserver votre numéro de dossier. L’administration étudiera votre demande et vous contactera pour la suite, in shaa Allah.\n\n"
            .sprintf("_%s_\n", $schoolName)
            .sprintf("_Contact WhatsApp : %s_\n\n\n", $this->formatWhatsappForDisplay($this->schoolWhatsapp($inscription->getEcole())))
            .sprintf("Message envoyé via *SALSABIL Madrassas* pour le compte de *%s*.", $schoolName);

        $this->sendAndRecord($inscription, static fn (GreenApiClient $client) => $client->sendTextMessage($phone, $message, $inscription->getEcole()));
        $this->sendProvisionalPdf($inscription, $phone);
        $this->notifySectionGeneralInvitation($inscription);
    }

    public function notifyInscriptionValidated(Inscription $inscription, Etudiant $etudiant): void
    {
        $phone = $this->candidatePhone($inscription);
        if (!$phone) {
            return;
        }

        $message = sprintf(
            "Assalamou aleykoum,\nVotre inscription à *%s* a été validée.\n\n*Nom :* %s\n*Matricule :* %s\n*Classe :* %s\n*Section :* %s\n*Niveau :* %s\n\nVotre fiche d’inscription vous est transmise avec ce message.\n\n_%s_\nWhatsApp : %s\n\n%s",
            $this->schoolName($inscription),
            $inscription->getNomComplet(),
            $etudiant->getMatricule() ?: '-',
            $inscription->getClasseFinale()?->getNom() ?: '-',
            $inscription->getSectionFinale()?->getNom() ?: '-',
            $inscription->getNiveauFinal()?->getNom() ?: '-',
            $this->schoolName($inscription),
            $this->schoolWhatsapp($inscription->getEcole()),
            $this->platformFooter($inscription->getEcole())
        );

        $this->sendAndRecord($inscription, static fn (GreenApiClient $client) => $client->sendTextMessage($phone, $message, $inscription->getEcole()));
        $this->sendPdfFile($inscription, $phone, $inscription->getFichePdfPath(), 'Fiche d’inscription - '.$this->schoolName($inscription));
        $this->notifyClassGroupInvitation($inscription);
    }

    public function notifyInscriptionRejected(Inscription $inscription): void
    {
        $phone = $this->candidatePhone($inscription);
        if (!$phone) {
            return;
        }

        $message = sprintf(
            "Assalamou aleykoum,\nVotre demande d’inscription à *%s* n’a pas pu être validée pour le moment.\n\n*Motif :* %s\n\nPour plus d’informations, contactez l’administration.\n\n_%s_\nWhatsApp : %s\n\n%s",
            $this->schoolName($inscription),
            $inscription->getMotifRejet() ?: 'Non précisé',
            $this->schoolName($inscription),
            $this->schoolWhatsapp($inscription->getEcole()),
            $this->platformFooter($inscription->getEcole())
        );

        $this->sendAndRecord($inscription, static fn (GreenApiClient $client) => $client->sendTextMessage($phone, $message, $inscription->getEcole()));
    }

    public function notifyGroupInvitation(Inscription $inscription, Classe $classe): void
    {
        $this->notifyClassGroupInvitation($inscription, $classe);
    }

    private function notifySectionGeneralInvitation(Inscription $inscription): void
    {
        $section = $inscription->getSectionSouhaitee() ?: $inscription->getSectionFinale();
        if (!$section) {
            return;
        }

        $this->sendGroupAccess(
            $inscription,
            $section->getWhatsappGroupId(),
            $section->getWhatsappGroupInviteLink(),
            sprintf(
                "Voici le lien du groupe général WhatsApp de la section *%s* :",
                $section->getNom() ?: 'sélectionnée'
            ),
            sprintf(
                'Vous avez été ajouté(e) au groupe général WhatsApp de la section %s.',
                $section->getNom() ?: 'sélectionnée'
            ),
            $section,
        );
    }

    private function notifyClassGroupInvitation(Inscription $inscription, ?Classe $classe = null): void
    {
        $classe ??= $inscription->getClasseFinale();
        if (!$classe) {
            return;
        }

        $this->sendGroupAccess(
            $inscription,
            $classe->getWhatsappGroupId(),
            $classe->getWhatsappGroupInviteLink(),
            sprintf(
                "Voici le lien du groupe WhatsApp de votre classe *%s* :",
                $classe->getNom() ?: 'votre classe'
            ),
            sprintf(
                'Vous avez été ajouté(e) au groupe WhatsApp de votre classe %s.',
                $classe->getNom() ?: ''
            ),
            $classe->getSection(),
        );
    }

    private function sendGroupAccess(
        Inscription $inscription,
        ?string $groupId,
        ?string $inviteLink,
        string $inviteMessage,
        string $addedMessage,
        ?Section $section = null,
    ): void {
        $phone = $this->candidatePhone($inscription);
        if (!$phone) {
            return;
        }

        if ($groupId) {
            $result = $this->safeGreenApiCall($inscription, static fn (GreenApiClient $client) => $client->addContactToGroup($groupId, $phone, $inscription->getEcole()));
            if ($result['success']) {
                $this->sendAndRecord($inscription, static fn (GreenApiClient $client) => $client->sendTextMessage($phone, $addedMessage, $inscription->getEcole()));
                return;
            }
            $inscription->setWhatsappLastError($result['message']);
            $inviteLink ??= $this->greenApi->getGroupInviteLink($groupId, $inscription->getEcole());
        }

        if ($inviteLink) {
            $result = $this->safeGreenApiCall($inscription, static fn (GreenApiClient $client) => $client->sendGroupInvite($phone, $inviteLink, $inviteMessage, $inscription->getEcole()));
            $this->recordResult($inscription, $result);

            return;
        }

        $this->logger->info('whatsapp_notification.group_not_configured', [
            'inscription_id' => $inscription->getId(),
            'numero_dossier' => $inscription->getNumeroDossier(),
            'section' => $section?->getNom(),
        ]);
        $this->entityManager->flush();
    }

    private function recordResult(Inscription $inscription, array $result): void
    {
        if ($result['success']) {
            $inscription->setWhatsappNotificationSentAt(new \DateTimeImmutable());
            $inscription->setWhatsappLastError(null);
        } else {
            $inscription->setWhatsappLastError($result['message']);
        }

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

    private function sendAndRecord(Inscription $inscription, callable $sender): void
    {
        try {
            $this->recordResult($inscription, $this->safeGreenApiCall($inscription, $sender));
        } catch (\Throwable $exception) {
            $this->logger->error('whatsapp_notification.record_failed_without_blocking', [
                'inscription_id' => $inscription->getId(),
                'numero_dossier' => $inscription->getNumeroDossier(),
                'exception' => $exception,
            ]);
        }
    }

    private function sendProvisionalPdf(Inscription $inscription, string $phone): void
    {
        try {
            $relativePath = $inscription->getFichePdfPath() ?: $this->pdfGenerator->generate($inscription);
            $inscription->setFichePdfPath($relativePath);
            $this->entityManager->flush();

            $this->sendPdfFile($inscription, $phone, $relativePath, 'Fiche provisoire d’inscription - '.$this->schoolName($inscription));
        } catch (\Throwable $exception) {
            $this->logger->error('whatsapp_notification.provisional_pdf_failed_without_blocking', [
                'inscription_id' => $inscription->getId(),
                'numero_dossier' => $inscription->getNumeroDossier(),
                'exception' => $exception,
            ]);
            $inscription->setWhatsappLastError($exception->getMessage());
            $this->entityManager->flush();
        }
    }

    private function sendPdfFile(Inscription $inscription, string $phone, ?string $relativePath, string $caption): void
    {
        if (!$relativePath) {
            return;
        }

        $fileName = basename($relativePath);
        $absolutePath = $this->projectDir.'/public/'.ltrim($relativePath, '/');
        $this->sendAndRecord($inscription, static fn (GreenApiClient $client) => $client->sendFileByUpload($phone, $absolutePath, $fileName, $caption, $inscription->getEcole()));
    }

    /** @return array{success: bool, message: string, data?: mixed, chatId?: string} */
    private function safeGreenApiCall(Inscription $inscription, callable $sender): array
    {
        try {
            return $sender($this->greenApi);
        } catch (\Throwable $exception) {
            $this->logger->error('whatsapp_notification.failed_without_blocking', [
                'inscription_id' => $inscription->getId(),
                'numero_dossier' => $inscription->getNumeroDossier(),
                'exception' => $exception,
            ]);

            return ['success' => false, 'message' => $exception->getMessage()];
        }
    }

    private function candidatePhone(Inscription $inscription): ?string
    {
        return $inscription->getTelephoneWhatsapp() ?: $inscription->getTelephonePrincipal();
    }

    private function schoolName(Inscription $inscription): string
    {
        return $inscription->getEcole()?->getNom() ?: 'la madrassa';
    }

    private function schoolWhatsapp(?Ecole $ecole): string
    {
        return $ecole?->getWhatsapp() ?: $ecole?->getTelephone1() ?: 'non renseigné';
    }

    private function platformFooter(?Ecole $ecole): string
    {
        return 'Message envoyé via SALSABIL Madrassas pour le compte de '.($ecole?->getNom() ?: 'la madrassa').'.';
    }

    private function formatWhatsappForDisplay(string $phone): string
    {
        $digits = preg_replace('/\D+/', '', $phone) ?: '';
        if (preg_match('/^237([0-9]{3})([0-9]{2})([0-9]{2})([0-9]{2})$/', $digits, $matches)) {
            return sprintf('+237 %s %s %s %s', $matches[1], $matches[2], $matches[3], $matches[4]);
        }

        if (preg_match('/^([0-9]{3})([0-9]{2})([0-9]{2})([0-9]{2})$/', $digits, $matches)) {
            return sprintf('%s %s %s %s', $matches[1], $matches[2], $matches[3], $matches[4]);
        }

        return trim($phone) ?: 'non renseigné';
    }

    private function statusLabel(string $status): string
    {
        return match ($status) {
            Inscription::STATUT_A_TESTER => 'À tester',
            Inscription::STATUT_A_AFFECTER => 'À affecter',
            Inscription::STATUT_VALIDEE => 'Validée',
            Inscription::STATUT_REJETEE => 'Rejetée',
            default => 'En attente de traitement',
        };
    }
}
