<?php

namespace App\Tests\Policy;

use App\Policy\Service\OperatorRegistry;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

/**
 * یازده عملگر، هر کدام روی هر دو نتیجه.
 *
 * عملگری که غلط بسنجد قانونی می‌سازد که یا همیشه می‌گیرد یا هرگز — و هیچ‌کدام خطا
 * نمی‌دهند. تست واحد است نه یکپارچه، چون خودِ مقایسه تابعی خالص است.
 */
class OperatorRegistryTest extends TestCase
{
    private const NOW = 1_800_000_000;

    #[DataProvider('cases')]
    public function testOperatorDecides(string $op, mixed $actual, mixed $expected, bool $result): void
    {
        self::assertSame(
            $result,
            (new OperatorRegistry())->evaluate($op, $actual, $expected, self::NOW),
            sprintf('%s(%s, %s)', $op, json_encode($actual), json_encode($expected)),
        );
    }

    public static function cases(): array
    {
        $day = 86400;

        return [
            'equals'              => ['equals', 5, 5, true],
            'equals — رشتهٔ عددی' => ['equals', '5', 5, true],
            'equals — نه'         => ['equals', 5, 6, false],
            'not_equals'          => ['not_equals', 5, 6, true],
            'greater_than'        => ['greater_than', 6, 5, true],
            'greater_than — مرز'  => ['greater_than', 5, 5, false],
            'greater_or_equal'    => ['greater_or_equal', 5, 5, true],
            'less_than'           => ['less_than', 4, 5, true],
            'less_or_equal'       => ['less_or_equal', 5, 5, true],
            'in'                  => ['in', 2, [1, 2, 3], true],
            'in — نه'             => ['in', 9, [1, 2, 3], false],
            'not_in'              => ['not_in', 9, [1, 2, 3], true],
            'between — داخل'      => ['between', 30, [18, 65], true],
            'between — مرز پایین' => ['between', 18, [18, 65], true],
            'between — مرز بالا'  => ['between', 65, [18, 65], true],
            'between — بیرون'     => ['between', 66, [18, 65], false],
            'contains'            => ['contains', ['vip', 'new'], 'vip', true],
            'contains — نه'       => ['contains', ['new'], 'vip', false],
            'days_since — گذشته'  => ['days_since', self::NOW - 40 * $day, 30, true],
            'days_since — تازه'   => ['days_since', self::NOW - 10 * $day, 30, false],
            'days_since — هرگز'   => ['days_since', 0, 30, false],
        ];
    }

    /** عملگر ناشناخته `false` می‌دهد، نه خطا — ولی ذخیره‌اش از قبل جلوگیری شده. */
    public function testAnUnknownOperatorIsFalseAndNotRegistered(): void
    {
        $registry = new OperatorRegistry();

        self::assertFalse($registry->has('regex'));
        self::assertFalse($registry->evaluate('regex', 'a', 'a'));
    }

    /** فرم فقط عملگرهای معنادار همان نوع را نشان می‌دهد. */
    public function testOperatorsAreFilteredByFieldType(): void
    {
        $registry = new OperatorRegistry();

        self::assertSame(['contains'], $registry->forType('list'));
        self::assertSame(['equals'], $registry->forType('bool'));
        self::assertContains('days_since', $registry->forType('timestamp'));
        self::assertNotContains('between', $registry->forType('uuid'));
    }
}
