<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Tests\Controller;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Controller\Admin\ProductReviewModerationController;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;

final class ProductReviewModerationControllerTest extends TestCase
{
    #[DataProvider('invalidRatingProvider')]
    public function testInvalidOrEmptyRatingFilterIsIgnored(string $rating): void
    {
        $reflection = new \ReflectionClass(ProductReviewModerationController::class);
        $controller = $reflection->newInstanceWithoutConstructor();
        $resolveFilters = $reflection->getMethod('resolveFilters');

        /** @var array{search: string, product: string, rating: int, status: string} $filters */
        $filters = $resolveFilters->invoke($controller, new Request([
            'rating' => $rating,
        ]));

        self::assertSame(0, $filters['rating']);
    }

    /** @return iterable<string, array{string}> */
    public static function invalidRatingProvider(): iterable
    {
        yield 'empty selection' => [''];
        yield 'unexpected value' => ['rating'];
    }

    #[DataProvider('validRatingProvider')]
    public function testValidRatingFilterIsPreserved(string $rating, int $expectedRating): void
    {
        $reflection = new \ReflectionClass(ProductReviewModerationController::class);
        $controller = $reflection->newInstanceWithoutConstructor();
        $resolveFilters = $reflection->getMethod('resolveFilters');

        /** @var array{search: string, product: string, rating: int, status: string} $filters */
        $filters = $resolveFilters->invoke($controller, new Request([
            'rating' => $rating,
        ]));

        self::assertSame($expectedRating, $filters['rating']);
    }

    public function testPendingStatusFilterIsPreserved(): void
    {
        $reflection = new \ReflectionClass(ProductReviewModerationController::class);
        $controller = $reflection->newInstanceWithoutConstructor();
        $resolveFilters = $reflection->getMethod('resolveFilters');

        /** @var array{search: string, product: string, rating: int, status: string} $filters */
        $filters = $resolveFilters->invoke($controller, new Request([
            'status' => 'pending',
        ]));

        self::assertSame('pending', $filters['status']);
    }

    public function testUnknownStatusFilterFallsBackToAll(): void
    {
        $reflection = new \ReflectionClass(ProductReviewModerationController::class);
        $controller = $reflection->newInstanceWithoutConstructor();
        $resolveFilters = $reflection->getMethod('resolveFilters');

        /** @var array{search: string, product: string, rating: int, status: string} $filters */
        $filters = $resolveFilters->invoke($controller, new Request([
            'status' => 'unknown',
        ]));

        self::assertSame('all', $filters['status']);
    }

    public function testDefaultStatusIsNotAddedToActionRedirects(): void
    {
        $reflection = new \ReflectionClass(ProductReviewModerationController::class);
        $controller = $reflection->newInstanceWithoutConstructor();
        $filterQuery = $reflection->getMethod('filterQuery');

        self::assertSame([], $filterQuery->invoke($controller, new Request()));
        self::assertSame(
            ['status' => 'pending'],
            $filterQuery->invoke($controller, new Request(['status' => 'pending'])),
        );
    }

    /** @return iterable<string, array{string, int}> */
    public static function validRatingProvider(): iterable
    {
        yield 'minimum rating' => ['1', 1];
        yield 'maximum rating' => ['5', 5];
    }

    public function testDedicatedModerationPageUsesAReadOnlyGetRoute(): void
    {
        $method = new \ReflectionMethod(ProductReviewModerationController::class, 'moderate');
        $attributes = $method->getAttributes(Route::class);

        self::assertCount(1, $attributes);

        /** @var Route $route */
        $route = $attributes[0]->newInstance();

        self::assertSame('/{id}', $route->path);
        self::assertSame('admin_marketing_product_review_moderate', $route->name);
        self::assertSame(['GET'], $route->methods);
    }

    public function testDedicatedModerationTemplatePostsProtectedActions(): void
    {
        $template = file_get_contents(
            __DIR__ . '/../../src/Bridge/Symfony/Bundle/Resources/views/admin/marketing/product_review/moderate.html.twig',
        );

        self::assertIsString($template);
        self::assertStringContainsString("path('admin_marketing_product_review_publish'", $template);
        self::assertStringContainsString("csrf_token('publish-review-'", $template);
        self::assertStringContainsString("path('admin_marketing_product_review_reject'", $template);
        self::assertStringContainsString("csrf_token('reject-review-'", $template);
        self::assertStringNotContainsString('method="get" action=', $template);
    }
}
