<?php

declare(strict_types=1);

use App\Services\Supplier\SupplierQuotaAllocator;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Tests\TestCase;

uses(TestCase::class);

// 2026-05-12 — это вторник (isoWeekday=2 в Europe/Moscow).
// 2026-05-16 — суббота (isoWeekday=6), 2026-05-17 — воскресенье (isoWeekday=7).

test('site signal distributes B1 ceil(total/3), B2 ceil(remainder/2), B3 remainder', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 10, 'workdays' => [1, 2, 3, 4, 5], 'regions' => []],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b2 = SupplierQuotaAllocator::allocate('B2', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b3 = SupplierQuotaAllocator::allocate('B3', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b2)->not->toBeNull()
        ->and($b3)->not->toBeNull()
        ->and($b1->limit + $b2->limit + $b3->limit)->toBe(10)
        ->and($b1->limit)->toBe(4)
        ->and($b2->limit)->toBe(3)
        ->and($b3->limit)->toBe(3);
});

test('call signal same distribution as site (B1/B2/B3 split)', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 30, 'workdays' => [1, 2, 3, 4, 5], 'regions' => []],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'call', '79991234567', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b1->limit)->toBe(10);
});

test('sms with keyword distributes B2+B3 only (B1 returns 0)', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 4, 'workdays' => [1, 2, 3, 4, 5], 'regions' => []],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'sms', 'TINKOFF+ипотека', $projects, Carbon::parse('2026-05-12'));
    $b2 = SupplierQuotaAllocator::allocate('B2', 'sms', 'TINKOFF+ипотека', $projects, Carbon::parse('2026-05-12'));
    $b3 = SupplierQuotaAllocator::allocate('B3', 'sms', 'TINKOFF+ипотека', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b2)->not->toBeNull()
        ->and($b3)->not->toBeNull()
        ->and($b1->limit)->toBe(0)
        ->and($b2->limit)->toBe(2)
        ->and($b3->limit)->toBe(2);
});

test('returns null when no active liderra projects on target weekday', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 10, 'workdays' => [6, 7], 'regions' => []],
    ]);

    $allocation = SupplierQuotaAllocator::allocate(
        'B1',
        'site',
        'example.com',
        $projects,
        Carbon::parse('2026-05-12'),
    );

    expect($allocation)->toBeNull();
});

test('workdays union deduplicates and sorts', function (): void {
    // Targeting Wednesday (2026-05-13, isoWeekday=3): оба проекта содержат 3 → оба eligible,
    // союз их workdays — [1,2,3,4,5].
    $projects = new Collection([
        (object) ['daily_limit' => 5, 'workdays' => [1, 2, 3], 'regions' => []],
        (object) ['daily_limit' => 5, 'workdays' => [3, 4, 5], 'regions' => []],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-13'));

    expect($b1)->not->toBeNull()
        ->and($b1->workdays)->toBe([1, 2, 3, 4, 5]);
});

test('regions union deduplicates and sorts', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 5, 'workdays' => [1, 2, 3, 4, 5], 'regions' => [77, 50]],
        (object) ['daily_limit' => 5, 'workdays' => [1, 2, 3, 4, 5], 'regions' => [50, 78]],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b1->regions)->toBe([50, 77, 78]);
});

test('empty regions stays empty (all regions semantics)', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 5, 'workdays' => [1, 2, 3, 4, 5], 'regions' => []],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b1->regions)->toBe([]);
});

test('single project with limit=1 sites to B1 only', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 1, 'workdays' => [1, 2, 3, 4, 5], 'regions' => []],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b2 = SupplierQuotaAllocator::allocate('B2', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b3 = SupplierQuotaAllocator::allocate('B3', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b2)->not->toBeNull()
        ->and($b3)->not->toBeNull()
        ->and($b1->limit)->toBe(1)
        ->and($b2->limit)->toBe(0)
        ->and($b3->limit)->toBe(0);
});

test('large scale: 1000 projects with limit 10 each = 10000 total', function (): void {
    $projects = new Collection(array_fill(0, 1000, (object) [
        'daily_limit' => 10,
        'workdays' => [1, 2, 3, 4, 5],
        'regions' => [],
    ]));

    $b1 = SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b2 = SupplierQuotaAllocator::allocate('B2', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b3 = SupplierQuotaAllocator::allocate('B3', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b2)->not->toBeNull()
        ->and($b3)->not->toBeNull()
        ->and($b1->limit + $b2->limit + $b3->limit)->toBe(10000)
        ->and($b1->limit)->toBe(3334);
});

test('odd total: 7 distributes B1=3, B2=2, B3=2', function (): void {
    $projects = new Collection([
        (object) ['daily_limit' => 7, 'workdays' => [1, 2, 3, 4, 5], 'regions' => []],
    ]);

    $b1 = SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b2 = SupplierQuotaAllocator::allocate('B2', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));
    $b3 = SupplierQuotaAllocator::allocate('B3', 'site', 'example.com', $projects, Carbon::parse('2026-05-12'));

    expect($b1)->not->toBeNull()
        ->and($b2)->not->toBeNull()
        ->and($b3)->not->toBeNull()
        ->and($b1->limit)->toBe(3)
        ->and($b2->limit)->toBe(2)
        ->and($b3->limit)->toBe(2);
});
