<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Tests\EventListener;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Context\GroupContext;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\EventListener\SitemapPopulateListener;
use CpCreation\VitiCore\Locale\Model\Locale;
use CpCreation\VitiCore\Locale\Repository\LocaleRepository;
use CpCreation\VitiCore\News\Model\News;
use CpCreation\VitiCore\News\Model\Translation\NewsTranslation;
use CpCreation\VitiCore\News\Repository\NewsRepository;
use CpCreation\VitiCore\Product\Repository\ProductCategoryRepository;
use CpCreation\VitiCore\Product\Repository\ProductRepository;
use CpCreation\VitiCore\Shop\Repository\ShopConfigRepository;
use CpCreation\VitiCore\Shop\Model\ShopConfig;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use PHPUnit\Framework\TestCase;
use Presta\SitemapBundle\Event\SitemapPopulateEvent;
use Presta\SitemapBundle\Service\UrlContainerInterface;
use Presta\SitemapBundle\Sitemap\Url\Url;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouterInterface;

final class SitemapPopulateListenerTest extends TestCase
{
    protected function tearDown(): void
    {
        GroupContext::$groupId = null;
    }

    public function testRegistersPublishedNewsWithLocalizedAlternates(): void
    {
        $routes = new RouteCollection();
        $routes->add('news_category.fr', new Route(
            '/les-actualites/{slug}',
            ['_locale' => 'fr', '_canonical_route' => 'news_category'],
            options: ['sitemap' => false],
        ));
        $routes->add('news_category.en', new Route(
            '/en/the-news/{slug}',
            ['_locale' => 'en', '_canonical_route' => 'news_category'],
            options: ['sitemap' => false],
        ));

        $router = $this->createMock(RouterInterface::class);
        $router->method('getRouteCollection')->willReturn($routes);
        $urlGenerator = new UrlGenerator(
            $routes,
            new RequestContext('', 'GET', 'example.com', 'https'),
        );

        $news = new News();
        $frenchTranslation = $news->translate('fr');
        self::assertInstanceOf(NewsTranslation::class, $frenchTranslation);
        $frenchTranslation->setSlug('actualite-francaise');
        $englishTranslation = $news->translate('en');
        self::assertInstanceOf(NewsTranslation::class, $englishTranslation);
        $englishTranslation->setSlug('english-news');

        $newsRepository = $this->createMock(NewsRepository::class);
        $newsRepository->expects(self::once())
            ->method('findAvailableAndPublish')
            ->willReturn([$news]);

        $english = new Locale();
        $english->setLocale('en');
        $localeRepository = $this->createMock(LocaleRepository::class);
        $localeRepository->method('findBy')->with(['disabled' => 0])->willReturn([$english]);

        $urlContainer = $this->createMock(UrlContainerInterface::class);
        $urlContainer->expects(self::once())
            ->method('addUrl')
            ->with(
                self::callback(static function (Url $url): bool {
                    $xml = $url->toXml();

                    self::assertStringContainsString(
                        '<loc>https://example.com/les-actualites/actualite-francaise</loc>',
                        $xml,
                    );
                    self::assertStringContainsString(
                        'hreflang="fr" href="https://example.com/les-actualites/actualite-francaise"',
                        $xml,
                    );
                    self::assertStringContainsString(
                        'hreflang="en" href="https://example.com/en/the-news/english-news"',
                        $xml,
                    );

                    return true;
                }),
                'news',
            );

        $listener = new SitemapPopulateListener(
            $router,
            $urlGenerator,
            $this->createStub(ProductCategoryRepository::class),
            $this->createStub(ProductRepository::class),
            $this->createStub(ShopConfigRepository::class),
            $this->createStub(CacheManager::class),
            $localeRepository,
            $newsRepository,
        );

        $listener->populate(new SitemapPopulateEvent($urlContainer, $urlGenerator, 'news'));
    }

    public function testFiltersShopProductsWithTheCurrentPriceGroup(): void
    {
        GroupContext::$groupId = 'default-group-id';

        $routes = new RouteCollection();
        $router = $this->createMock(RouterInterface::class);
        $router->method('getRouteCollection')->willReturn($routes);
        $urlGenerator = new UrlGenerator($routes, new RequestContext());

        $productRepository = $this->createMock(ProductRepository::class);
        $productRepository->expects(self::once())
            ->method('findOnlyShop')
            ->with('default-group-id')
            ->willReturn([]);

        $shopConfig = new ShopConfig();
        $shopConfig->setEnableProductPageFront(true);
        $shopConfigRepository = $this->createMock(ShopConfigRepository::class);
        $shopConfigRepository->method('findOne')->willReturn($shopConfig);

        $urlContainer = $this->createMock(UrlContainerInterface::class);
        $urlContainer->expects(self::never())->method('addUrl');

        $listener = new SitemapPopulateListener(
            $router,
            $urlGenerator,
            $this->createStub(ProductCategoryRepository::class),
            $productRepository,
            $shopConfigRepository,
            $this->createStub(CacheManager::class),
            $this->createStub(LocaleRepository::class),
            $this->createStub(NewsRepository::class),
        );

        $listener->populate(new SitemapPopulateEvent($urlContainer, $urlGenerator, 'shop_products'));
    }

    public function testDoesNotRegisterShopCategoriesWhenCategoryMenuIsDisabled(): void
    {
        $routes = new RouteCollection();
        $routes->add('shop.fr', new Route(
            '/boutique/{slug}',
            ['_locale' => 'fr', '_canonical_route' => 'shop', 'slug' => null],
        ));

        $router = $this->createMock(RouterInterface::class);
        $router->method('getRouteCollection')->willReturn($routes);
        $urlGenerator = new UrlGenerator(
            $routes,
            new RequestContext('', 'GET', 'example.com', 'https'),
        );

        $shopConfig = new ShopConfig();
        $shopConfig->setShowCategoryMenuFront(false);
        $shopConfigRepository = $this->createMock(ShopConfigRepository::class);
        $shopConfigRepository->expects(self::once())
            ->method('findOne')
            ->willReturn($shopConfig);

        $productCategoryRepository = $this->createMock(ProductCategoryRepository::class);
        $productCategoryRepository->expects(self::never())->method('findOnlyShop');

        $urlContainer = $this->createMock(UrlContainerInterface::class);
        $urlContainer->expects(self::never())->method('addUrl');

        $listener = new SitemapPopulateListener(
            $router,
            $urlGenerator,
            $productCategoryRepository,
            $this->createStub(ProductRepository::class),
            $shopConfigRepository,
            $this->createStub(CacheManager::class),
            $this->createStub(LocaleRepository::class),
            $this->createStub(NewsRepository::class),
        );

        $listener->populate(new SitemapPopulateEvent($urlContainer, $urlGenerator, 'shop_categories'));
    }
}
