<?php

declare(strict_types=1);

namespace App\Controller\Platform;

use App\Entity\Ecole;
use App\Entity\TenantDomain;
use App\Form\EcoleType;
use App\Repository\EcoleRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

#[Route('/platform/ecoles', name: 'platform_ecole_')]
#[IsGranted('ROLE_SUPER_ADMIN')]
final class EcoleController extends AbstractController
{
    #[Route('', name: 'index', methods: ['GET'])]
    public function index(EcoleRepository $ecoleRepository, UserRepository $userRepository): Response
    {
        $ecoles = $ecoleRepository->findBy([], ['createdAt' => 'DESC']);
        $adminCounts = [];

        foreach ($ecoles as $ecole) {
            $adminCounts[$ecole->getId()] = $userRepository->countAdminsForEcole((int) $ecole->getId());
        }

        return $this->render('platform/ecole/index.html.twig', [
            'ecoles' => $ecoles,
            'adminCounts' => $adminCounts,
        ]);
    }

    #[Route('/new', name: 'new', methods: ['GET', 'POST'])]
    public function new(Request $request, EntityManagerInterface $entityManager): Response
    {
        $ecole = new Ecole();
        $ecole->setPays('Cameroun');

        $form = $this->createForm(EcoleType::class, $ecole);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->handleIdentityUploads($ecole, $form);
            $this->syncTenantDomains($ecole, $form);
            $entityManager->persist($ecole);
            $entityManager->flush();

            $this->addFlash('success', 'La madrassa a été créée avec succès.');

            return $this->redirectToRoute('platform_ecole_index', [], Response::HTTP_SEE_OTHER);
        }

        return $this->render('platform/ecole/new.html.twig', [
            'ecole' => $ecole,
            'form' => $form,
        ]);
    }

    #[Route('/{id}', name: 'show', requirements: ['id' => '\d+'], methods: ['GET'])]
    public function show(Ecole $ecole, UserRepository $userRepository): Response
    {
        return $this->render('platform/ecole/show.html.twig', [
            'ecole' => $ecole,
            'adminCount' => $userRepository->countAdminsForEcole((int) $ecole->getId()),
        ]);
    }

    #[Route('/{id}/edit', name: 'edit', requirements: ['id' => '\d+'], methods: ['GET', 'POST'])]
    public function edit(Request $request, Ecole $ecole, EntityManagerInterface $entityManager): Response
    {
        $form = $this->createForm(EcoleType::class, $ecole);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->handleIdentityUploads($ecole, $form);
            $this->syncTenantDomains($ecole, $form);
            $entityManager->flush();

            $this->addFlash('success', 'La madrassa a été mise à jour.');

            return $this->redirectToRoute('platform_ecole_index', [], Response::HTTP_SEE_OTHER);
        }

        return $this->render('platform/ecole/edit.html.twig', [
            'ecole' => $ecole,
            'form' => $form,
        ]);
    }

    #[Route('/{id}/delete', name: 'delete', requirements: ['id' => '\d+'], methods: ['POST'])]
    public function delete(Request $request, Ecole $ecole, EntityManagerInterface $entityManager): Response
    {
        if ($this->isCsrfTokenValid('delete_ecole_'.$ecole->getId(), (string) $request->request->get('_token'))) {
            $entityManager->remove($ecole);
            $entityManager->flush();

            $this->addFlash('success', 'La madrassa a été supprimée.');
        }

        return $this->redirectToRoute('platform_ecole_index', [], Response::HTTP_SEE_OTHER);
    }

    /**
     * @param FormInterface<Ecole> $form
     */
    private function handleIdentityUploads(Ecole $ecole, FormInterface $form): void
    {
        $logoFile = $form->get('logoFile')->getData();
        if ($logoFile instanceof UploadedFile) {
            $ecole->setLogo($this->moveUploadedFile($logoFile, $ecole, 'logo'));
        }

        $faviconFile = $form->get('faviconFile')->getData();
        if ($faviconFile instanceof UploadedFile) {
            $ecole->setFavicon($this->moveUploadedFile($faviconFile, $ecole, 'favicon'));
        }

        $heroImageFile = $form->get('heroImageFile')->getData();
        if ($heroImageFile instanceof UploadedFile) {
            $ecole->setHeroImage($this->moveUploadedFile($heroImageFile, $ecole, 'hero'));
        }

        $presentationImage1File = $form->get('presentationImage1File')->getData();
        if ($presentationImage1File instanceof UploadedFile) {
            $ecole->setPresentationImage1($this->moveUploadedFile($presentationImage1File, $ecole, 'presentation-1'));
        }

        $presentationImage2File = $form->get('presentationImage2File')->getData();
        if ($presentationImage2File instanceof UploadedFile) {
            $ecole->setPresentationImage2($this->moveUploadedFile($presentationImage2File, $ecole, 'presentation-2'));
        }

        $presentationImage3File = $form->get('presentationImage3File')->getData();
        if ($presentationImage3File instanceof UploadedFile) {
            $ecole->setPresentationImage3($this->moveUploadedFile($presentationImage3File, $ecole, 'presentation-3'));
        }
    }

    private function moveUploadedFile(UploadedFile $file, Ecole $ecole, string $kind): string
    {
        $projectDir = (string) $this->getParameter('kernel.project_dir');
        $targetDir = $projectDir.'/public/uploads/ecoles';

        if (!is_dir($targetDir) && !mkdir($targetDir, 0775, true) && !is_dir($targetDir)) {
            throw new \RuntimeException(sprintf('Impossible de créer le dossier de téléversement "%s".', $targetDir));
        }

        $slug = $ecole->getSlug() ?: 'madrassa';
        $slug = preg_replace('/[^a-z0-9-]+/', '-', mb_strtolower($slug)) ?: 'madrassa';
        $slug = trim($slug, '-') ?: 'madrassa';

        $extension = $file->guessExtension() ?: $file->getClientOriginalExtension() ?: 'bin';
        $extension = mb_strtolower($extension);
        if ($extension === 'jpeg') {
            $extension = 'jpg';
        }

        $filename = sprintf('%s-%s-%s.%s', $slug, $kind, bin2hex(random_bytes(4)), $extension);
        $file->move($targetDir, $filename);

        return 'uploads/ecoles/'.$filename;
    }

    /**
     * @param FormInterface<Ecole> $form
     */
    private function syncTenantDomains(Ecole $ecole, FormInterface $form): void
    {
        $publicDomain = TenantDomain::normalizeHost((string) $this->getParameter('app.public_domain'));
        $canonicalHost = $this->canonicalHost($ecole, $publicDomain);
        $aliases = $this->aliasesFromText((string) $form->get('domainAliasesText')->getData(), $canonicalHost);

        $canonicalDomain = null;
        $existingByHost = [];
        foreach ($ecole->getTenantDomains() as $tenantDomain) {
            $host = $tenantDomain->getHost();
            if ($host !== null) {
                $existingByHost[$host] = $tenantDomain;
            }

            if ($tenantDomain->isCanonical()) {
                $tenantDomain->setCanonical(false);
                $canonicalDomain ??= $tenantDomain;
            }
        }

        if ($canonicalHost !== null) {
            $canonicalDomain = $existingByHost[$canonicalHost] ?? $canonicalDomain ?? new TenantDomain();
            $canonicalDomain
                ->setHost($canonicalHost)
                ->setCanonical(true)
                ->setActive(true);
            $ecole->addTenantDomain($canonicalDomain);
        }

        $existingAliases = [];
        foreach ($ecole->getTenantDomains() as $tenantDomain) {
            $host = $tenantDomain->getHost();
            if (!$tenantDomain->isCanonical() && $host !== null) {
                $existingAliases[$host] = $tenantDomain;
            }
        }

        foreach ($existingAliases as $host => $tenantDomain) {
            if (!in_array($host, $aliases, true)) {
                $ecole->removeTenantDomain($tenantDomain);
            }
        }

        foreach ($aliases as $alias) {
            $tenantDomain = $existingAliases[$alias] ?? new TenantDomain();
            $tenantDomain
                ->setHost($alias)
                ->setCanonical(false)
                ->setActive(true);
            $ecole->addTenantDomain($tenantDomain);
        }
    }

    private function canonicalHost(Ecole $ecole, string $publicDomain): ?string
    {
        $subdomain = TenantDomain::normalizeHost((string) $ecole->getSousDomaine());

        if ($subdomain === '' || $publicDomain === '') {
            return null;
        }

        return sprintf('%s.%s', $subdomain, $publicDomain);
    }

    /**
     * @return list<string>
     */
    private function aliasesFromText(string $aliasesText, ?string $canonicalHost): array
    {
        $aliases = [];

        foreach (preg_split('/\R+/', $aliasesText) ?: [] as $alias) {
            $host = TenantDomain::normalizeHost($alias);
            if ($host === '' || $host === $canonicalHost) {
                continue;
            }

            $aliases[$host] = $host;
        }

        return array_values($aliases);
    }
}
