<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Tests\Marketing;

use CpCreation\VitiCore\Marketing\ProductReviewCardSummaryProvider;
use CpCreation\VitiCore\Marketing\ProductReviewConfigurationProvider;
use CpCreation\VitiCore\Marketing\ProductReviewRatingSummary;
use CpCreation\VitiCore\Marketing\PublishedProductReviewRatingCollectionProvider;
use CpCreation\VitiCore\Product\Model\Product;
use PHPUnit\Framework\TestCase;

final class ProductReviewCardSummaryProviderTest extends TestCase
{
    public function testItOnlyExposesTheAverageFromThreePublishedReviews(): void
    {
        $visibleProduct = new Product();
        $hiddenProduct = new Product();
        $summaries = [
            $visibleProduct->getId()->toString() => new ProductReviewRatingSummary(3, 3.0),
            $hiddenProduct->getId()->toString() => new ProductReviewRatingSummary(2, 5.0),
        ];

        $provider = new ProductReviewCardSummaryProvider(
            $this->configuration(true),
            $this->ratingProvider($summaries),
        );

        $reviewData = $provider->getForProducts([$visibleProduct, $hiddenProduct]);

        self::assertTrue($reviewData->enabled);
        self::assertSame(3, $reviewData->summaries[$visibleProduct->getId()->toString()]->reviewCount);
        self::assertSame(3.0, $reviewData->summaries[$visibleProduct->getId()->toString()]->ratingValue);
        self::assertSame(2, $reviewData->summaries[$hiddenProduct->getId()->toString()]->reviewCount);
        self::assertNull($reviewData->summaries[$hiddenProduct->getId()->toString()]->ratingValue);
    }

    public function testItDoesNotLoadOrExposeRatingsWhenReviewsAreDisabled(): void
    {
        $ratingProvider = new class implements PublishedProductReviewRatingCollectionProvider {
            public bool $called = false;

            public function getPublishedRatingSummaries(
                iterable $products,
                ?\DateTimeImmutable $now = null,
            ): array {
                $this->called = true;

                return [];
            }
        };
        $provider = new ProductReviewCardSummaryProvider(
            $this->configuration(false),
            $ratingProvider,
        );

        $reviewData = $provider->getForProducts([new Product()]);

        self::assertFalse($reviewData->enabled);
        self::assertSame([], $reviewData->summaries);
        self::assertFalse($ratingProvider->called);
    }

    private function configuration(bool $enabled): ProductReviewConfigurationProvider
    {
        return new class ($enabled) implements ProductReviewConfigurationProvider {
            public function __construct(private readonly bool $enabled) {}

            public function isEnabled(): bool
            {
                return $this->enabled;
            }

            public function isModerationRequired(): bool
            {
                return false;
            }
        };
    }

    /**
     * @param array<string, ProductReviewRatingSummary> $summaries
     */
    private function ratingProvider(array $summaries): PublishedProductReviewRatingCollectionProvider
    {
        return new class ($summaries) implements PublishedProductReviewRatingCollectionProvider {
            /**
             * @param array<string, ProductReviewRatingSummary> $summaries
             */
            public function __construct(private readonly array $summaries) {}

            public function getPublishedRatingSummaries(
                iterable $products,
                ?\DateTimeImmutable $now = null,
            ): array {
                return $this->summaries;
            }
        };
    }
}
