<?php

/*
 * 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\Twig;

use CpCreation\VitiCore\AgeVerification\Repository\AgeVerificationConfigRepository;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\LocalizedRouting\LocalizedPageRouteResolver;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Provider\LocaleProvider;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Twig\Components\Site\AgeGate;
use CpCreation\VitiCore\News\Repository\NewsRepository;
use CpCreation\VitiCore\Product\Model\Product;
use CpCreation\VitiCore\Product\Model\ProductCategory;
use CpCreation\VitiCore\Product\Model\Translation\ProductCategoryTranslation;
use CpCreation\VitiCore\Product\Model\Translation\ProductTranslation;
use CpCreation\VitiCore\Product\Repository\ProductCategoryRepository;
use CpCreation\VitiCore\Product\Repository\ProductRepository;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
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;
use Symfony\Contracts\Translation\TranslatorInterface;

final class AgeGateLanguageUrlTest extends TestCase
{
    public function testItTranslatesTheShopCategorySlugForEachLanguage(): void
    {
        $category = $this->createCategory('champagne', 'champagne-1');

        $categoryRepository = $this->createMock(ProductCategoryRepository::class);
        $categoryRepository->expects(self::once())
            ->method('findOneBySlug')
            ->with('champagne')
            ->willReturn($category);

        $component = $this->createComponent(
            $categoryRepository,
            $this->createStub(ProductRepository::class),
        );
        $component->pageRoute = 'shop';
        $component->pageRouteParameters = ['slug' => 'champagne'];

        self::assertSame('/boutique/champagne', $component->getLanguageOptions()['fr']['url']);
        self::assertSame('/en/shop/champagne-1', $component->getLanguageOptions()['en']['url']);
    }

    public function testItTranslatesTheCategoryAndProductSlugsOnAProductPage(): void
    {
        $category = $this->createCategory('champagne', 'champagne-1');
        $product = new Product();
        $product->setCategory($category);

        $this->addProductTranslation($product, 'fr', 'la-seduisante-brut-1');
        $this->addProductTranslation($product, 'en', 'la-seduisante-brut');

        $productRepository = $this->createMock(ProductRepository::class);
        $productRepository->expects(self::once())
            ->method('findOneBySlug')
            ->with('la-seduisante-brut-1')
            ->willReturn($product);

        $component = $this->createComponent(
            $this->createStub(ProductCategoryRepository::class),
            $productRepository,
        );
        $component->pageRoute = 'shop_product';
        $component->pageRouteParameters = [
            'categorySlug' => 'champagne',
            'slug' => 'la-seduisante-brut-1',
        ];

        self::assertSame(
            '/boutique/champagne/la-seduisante-brut-1',
            $component->getLanguageOptions()['fr']['url'],
        );
        self::assertSame(
            '/en/shop/champagne-1/la-seduisante-brut',
            $component->getLanguageOptions()['en']['url'],
        );
    }

    public function testItPreservesRepeatedQueryParametersWhenChangingLanguage(): void
    {
        $category = $this->createCategory('champagne', 'champagne-1');
        $categoryRepository = $this->createMock(ProductCategoryRepository::class);
        $categoryRepository->expects(self::once())
            ->method('findOneBySlug')
            ->with('champagne')
            ->willReturn($category);

        $component = $this->createComponent(
            $categoryRepository,
            $this->createStub(ProductRepository::class),
            '/boutique?tag=one&tag=two&utm_source=audit',
        );
        $component->countryCode = 'FR';
        $component->pageRoute = 'shop';
        $component->pageRouteParameters = ['slug' => 'champagne'];
        $component->mount();

        self::assertSame('tag=one&tag=two&utm_source=audit', $component->pageQueryString);
        self::assertSame(
            '/en/shop/champagne-1?tag=one&tag=two&utm_source=audit',
            $component->getLanguageOptions()['en']['url'],
        );
    }

    private function createCategory(string $frenchSlug, string $englishSlug): ProductCategory
    {
        $category = new ProductCategory();

        $this->addCategoryTranslation($category, 'fr', $frenchSlug);
        $this->addCategoryTranslation($category, 'en', $englishSlug);

        return $category;
    }

    private function createComponent(
        ProductCategoryRepository $categoryRepository,
        ProductRepository $productRepository,
        string $requestUri = '/boutique',
    ): AgeGate {
        $localeProvider = $this->createMock(LocaleProvider::class);
        $localeProvider->method('getLocales')->willReturn(['fr', 'en']);
        $localeProvider->method('getDefaultLocale')->willReturn('fr');

        $request = Request::create($requestUri);
        $request->setLocale('fr');
        $requestStack = new RequestStack();
        $requestStack->push($request);

        $routes = new RouteCollection();
        $routes->add('shop.fr', new Route('/boutique/{slug}', [
            '_canonical_route' => 'shop',
            '_locale' => 'fr',
            'slug' => null,
        ]));
        $routes->add('shop.en', new Route('/en/shop/{slug}', [
            '_canonical_route' => 'shop',
            '_locale' => 'en',
            'slug' => null,
        ]));
        $routes->add('shop_product.fr', new Route('/boutique/{categorySlug}/{slug}', [
            '_canonical_route' => 'shop_product',
            '_locale' => 'fr',
        ]));
        $routes->add('shop_product.en', new Route('/en/shop/{categorySlug}/{slug}', [
            '_canonical_route' => 'shop_product',
            '_locale' => 'en',
        ]));

        $generator = new UrlGenerator($routes, new RequestContext());
        $router = $this->createMock(RouterInterface::class);
        $router->method('getRouteCollection')->willReturn($routes);
        $router->method('generate')
            ->willReturnCallback(static fn (
                string $route,
                array $parameters = [],
                int $referenceType = 1,
            ): string => $generator->generate($route, $parameters, $referenceType));

        $localizedPageRouteResolver = new LocalizedPageRouteResolver(
            $requestStack,
            $router,
            $localeProvider,
            $this->createStub(NewsRepository::class),
            $categoryRepository,
            $productRepository,
        );

        return new AgeGate(
            (new \ReflectionClass(AgeVerificationConfigRepository::class))->newInstanceWithoutConstructor(),
            $localeProvider,
            $localizedPageRouteResolver,
            $requestStack,
            $router,
            $this->createStub(TranslatorInterface::class),
        );
    }

    private function addCategoryTranslation(ProductCategory $category, string $locale, string $slug): void
    {
        $translation = new ProductCategoryTranslation();
        $translation->setLocale($locale);
        $translation->setName($slug);
        $translation->setSlug($slug);
        $category->addTranslation($translation);
    }

    private function addProductTranslation(Product $product, string $locale, string $slug): void
    {
        $translation = new ProductTranslation();
        $translation->setLocale($locale);
        $translation->setName($slug);
        $translation->setDescription($slug);
        $translation->setSlug($slug);
        $product->addTranslation($translation);
    }
}
