<?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\Shop;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Context\GroupContext;
use CpCreation\VitiCore\Product\Model\Product;
use CpCreation\VitiCore\Product\Model\ProductCategory;
use CpCreation\VitiCore\Product\Model\ProductCollection;
use CpCreation\VitiCore\Product\Model\ProductPriceGroup;
use CpCreation\VitiCore\Product\Repository\ProductCategoryRepository;
use CpCreation\VitiCore\Product\Repository\ProductCollectionRepository;
use CpCreation\VitiCore\Product\Repository\ProductPriceGroupRepository;
use CpCreation\VitiCore\Product\Repository\ProductRepository;
use CpCreation\VitiCore\Shop\Model\ShopConfig;
use CpCreation\VitiCore\Shop\Repository\ShopConfigRepository;
use CpCreation\VitiCore\Shop\ShopCatalogResolver;
use PHPUnit\Framework\TestCase;

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

    public function testProductVisibilityUsesTheActivePublicPriceGroup(): void
    {
        $activeGroup = new ProductPriceGroup();
        $otherGroup = new ProductPriceGroup();
        GroupContext::$groupId = $activeGroup->getId()->toString();

        $product = new Product();
        $product->setCategory(new ProductCategory());
        $product->addGroup($otherGroup);

        $resolver = new ShopCatalogResolver(
            $this->createStub(ProductCategoryRepository::class),
            $this->createStub(ProductRepository::class),
            $this->createStub(ProductCollectionRepository::class),
            $this->createStub(ProductPriceGroupRepository::class),
            $this->createStub(ShopConfigRepository::class),
        );

        self::assertFalse($resolver->isProductVisibleInShop($product));

        $product->addGroup($activeGroup);

        self::assertTrue($resolver->isProductVisibleInShop($product));
    }

    public function testShopProductsContainsAllProductsWhenCategoryMenuIsHidden(): void
    {
        GroupContext::$groupId = null;

        $config = new ShopConfig();
        $config->setShowCategoryMenuFront(false);

        $firstCategory = new ProductCategory();
        $secondCategory = new ProductCategory();
        $firstProduct = new Product();
        $secondProduct = new Product();

        $categoryRepository = $this->createMock(ProductCategoryRepository::class);
        $categoryRepository->expects(self::once())
            ->method('findOnlyShop')
            ->with(null)
            ->willReturn([$firstCategory, $secondCategory]);

        $productRepository = $this->createMock(ProductRepository::class);
        $productRepository->expects(self::exactly(2))
            ->method('findOnlyShop')
            ->willReturnMap([
                [null, $firstCategory, [$firstProduct]],
                [null, $secondCategory, [$secondProduct]],
            ]);

        $priceGroupRepository = $this->createMock(ProductPriceGroupRepository::class);
        $priceGroupRepository->expects(self::once())
            ->method('getGroupByDefault')
            ->willReturn(null);

        $configRepository = $this->createMock(ShopConfigRepository::class);
        $configRepository->expects(self::once())
            ->method('findOne')
            ->willReturn($config);

        $resolver = new ShopCatalogResolver(
            $categoryRepository,
            $productRepository,
            $this->createMock(ProductCollectionRepository::class),
            $priceGroupRepository,
            $configRepository,
        );

        $catalog = $resolver->resolveCatalog();

        self::assertFalse($catalog['showCategoryMenu']);
        self::assertSame([$firstProduct, $secondProduct], $catalog['shopProducts']);
        self::assertSame([$firstProduct, $secondProduct], $catalog['allShopProducts']);
        self::assertCount(2, $catalog['shopProductGroups']);
    }

    public function testFutureCollectionIsIgnoredByTheShopCatalog(): void
    {
        $collection = new ProductCollection();
        $collection->setPublishedAt(new \DateTimeImmutable('2100-01-01 00:00:00'));

        $categoryRepository = $this->createMock(ProductCategoryRepository::class);
        $categoryRepository->expects(self::once())
            ->method('findOnlyShop')
            ->with(null)
            ->willReturn([]);

        $productRepository = $this->createMock(ProductRepository::class);
        $productRepository->expects(self::never())->method('findPublishedForProductCollection');

        $collectionRepository = $this->createMock(ProductCollectionRepository::class);
        $collectionRepository->expects(self::once())
            ->method('findOneByCode')
            ->with('champagnes')
            ->willReturn($collection);

        $priceGroupRepository = $this->createMock(ProductPriceGroupRepository::class);
        $priceGroupRepository->expects(self::once())
            ->method('getGroupByDefault')
            ->willReturn(null);

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

        $resolver = new ShopCatalogResolver(
            $categoryRepository,
            $productRepository,
            $collectionRepository,
            $priceGroupRepository,
            $configRepository,
        );

        $catalog = $resolver->resolveCatalog(
            source: ShopCatalogResolver::SOURCE_COLLECTION,
            collectionCode: 'champagnes',
        );

        self::assertNull($catalog['collection']);
        self::assertSame([], $catalog['shopProducts']);
    }
}
