<?php

namespace App\Controller;

use App\Entity\Event;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class SitemapController extends AbstractController
{
    private const MAX_URLS_PER_SITEMAP = 50000;
    private const CONTENT_TYPE_XML = 'text/xml';
    private const URLSET_TEMPLATE = 'sitemap/urlset.xml.twig';

    public function __construct(
        private readonly EntityManagerInterface $em,
    ) {
    }

    #[Route('/sitemap.xml', name: 'app_sitemap', methods: ['GET'])]
    public function index(): Response
    {
        $eventCount = $this->em->getRepository(Event::class)->count(['isOnline' => true, 'isSecret' => false]);
        $eventPages = max(1, (int) ceil($eventCount / self::MAX_URLS_PER_SITEMAP));

        $sitemaps = [
            ['loc' => $this->generateUrl('app_sitemap_main', [], UrlGeneratorInterface::ABSOLUTE_URL)],
        ];

        $allUsers = $this->em->getRepository(User::class)->findAll();
        $orgaCount = \count(array_filter($allUsers, fn (User $u) => \in_array('ROLE_ORGANIZER', $u->getRoles(), true) && $u->isApproved()));
        $orgaPages = max(1, (int) ceil($orgaCount / self::MAX_URLS_PER_SITEMAP));

        for ($i = 1; $i <= $eventPages; ++$i) {
            $sitemaps[] = [
                'loc' => $this->generateUrl('app_sitemap_events', ['page' => $i], UrlGeneratorInterface::ABSOLUTE_URL),
            ];
        }

        for ($i = 1; $i <= $orgaPages; ++$i) {
            $sitemaps[] = [
                'loc' => $this->generateUrl('app_sitemap_orgas', ['page' => $i], UrlGeneratorInterface::ABSOLUTE_URL),
            ];
        }

        return new Response(
            $this->renderView('sitemap/index.xml.twig', ['sitemaps' => $sitemaps]),
            200,
            ['Content-Type' => self::CONTENT_TYPE_XML],
        );
    }

    #[Route('/sitemap-main.xml', name: 'app_sitemap_main', methods: ['GET'])]
    public function main(Request $request): Response
    {
        $baseUrl = $request->getSchemeAndHttpHost();

        $pages = [
            ['app_home', 'daily', '1.0'],
            ['app_search', 'weekly', '0.5'],
            ['app_tarifs', 'monthly', '0.7'],
            ['app_events', 'daily', '0.9'],
            ['app_contact', 'yearly', '0.5'],
            ['app_mentions_legales', 'yearly', '0.3'],
            ['app_cgu', 'yearly', '0.3'],
            ['app_cgv', 'yearly', '0.3'],
            ['app_hosting', 'yearly', '0.2'],
            ['app_cookies', 'yearly', '0.2'],
            ['app_rgpd', 'yearly', '0.3'],
            ['app_conformite', 'yearly', '0.2'],
        ];

        $urls = array_map(fn (array $p) => $this->sitemapUrl($p[0], $p[1], $p[2]), $pages);

        $urls[] = $this->sitemapUrl('app_organizers', 'weekly', '0.8', [[
            'loc' => $baseUrl.'/logo.png',
            'title' => 'E-Ticket - Nos organisateurs',
        ]]);

        return new Response(
            $this->renderView(self::URLSET_TEMPLATE, ['urls' => $urls]),
            200,
            ['Content-Type' => self::CONTENT_TYPE_XML],
        );
    }

    #[Route('/sitemap-events-{page}.xml', name: 'app_sitemap_events', requirements: ['page' => '\d+'], methods: ['GET'])]
    public function events(Request $request, int $page = 1): Response
    {
        $baseUrl = $request->getSchemeAndHttpHost();

        return $this->renderUrlset($this->getEventUrls($baseUrl));
    }

    #[Route('/sitemap-orgas-{page}.xml', name: 'app_sitemap_orgas', requirements: ['page' => '\d+'], methods: ['GET'])]
    public function orgas(Request $request, int $page = 1): Response
    {
        $baseUrl = $request->getSchemeAndHttpHost();

        return $this->renderUrlset($this->getOrgaUrls($baseUrl));
    }

    /**
     * @param list<array<string, mixed>> $urls
     */
    private function renderUrlset(array $urls): Response
    {
        return new Response(
            $this->renderView(self::URLSET_TEMPLATE, ['urls' => $urls]),
            200,
            ['Content-Type' => self::CONTENT_TYPE_XML],
        );
    }

    /**
     * @return list<array<string, mixed>>
     */
    private function getEventUrls(string $baseUrl): array
    {
        $events = $this->em->getRepository(Event::class)->findBy(['isOnline' => true, 'isSecret' => false]);

        $urls = [];
        foreach ($events as $event) {
            $organizer = $event->getAccount();
            $url = [
                'loc' => $this->generateUrl('app_event_detail', [
                    'orgaSlug' => $organizer->getSlug(),
                    'id' => $event->getId(),
                    'eventSlug' => $event->getSlug(),
                ], UrlGeneratorInterface::ABSOLUTE_URL),
                'changefreq' => 'daily',
                'priority' => '0.8',
            ];

            if ($event->getEventMainPictureName()) {
                $url['images'] = [[
                    'loc' => $baseUrl.'/uploads/events/'.$event->getEventMainPictureName(),
                    'title' => $event->getTitle(),
                ]];
            }

            $urls[] = $url;
        }

        return $urls;
    }

    /**
     * @return list<array<string, mixed>>
     */
    private function getOrgaUrls(string $baseUrl): array
    {
        $allUsers = $this->em->getRepository(User::class)->findAll();
        $organizers = array_filter($allUsers, fn (User $u) => \in_array('ROLE_ORGANIZER', $u->getRoles(), true) && $u->isApproved());

        $urls = [];
        foreach ($organizers as $organizer) {
            $url = [
                'loc' => $this->generateUrl('app_organizer_detail', ['id' => $organizer->getId(), 'slug' => $organizer->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
                'changefreq' => 'weekly',
                'priority' => '0.6',
            ];

            if ($organizer->getLogoName()) {
                $url['images'] = [[
                    'loc' => $baseUrl.'/uploads/logos/'.$organizer->getLogoName(),
                    'title' => $organizer->getCompanyName() ?? $organizer->getFirstName().' '.$organizer->getLastName(),
                ]];
            }

            $urls[] = $url;
        }

        return $urls;
    }

    /**
     * @param list<array{loc: string, title: string}>|null $images
     *
     * @return array<string, mixed>
     */
    private function sitemapUrl(string $route, string $changefreq, string $priority, ?array $images = null): array
    {
        $url = [
            'loc' => $this->generateUrl($route, [], UrlGeneratorInterface::ABSOLUTE_URL),
            'changefreq' => $changefreq,
            'priority' => $priority,
        ];

        if ($images) {
            $url['images'] = $images;
        }

        return $url;
    }
}
