<?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-13 — среда (isoWeekday=3).

it('computeOrder = max(наибольший лимит, ceil(Σ/3))', function (array $limits, int $expected): void {
    expect(SupplierQuotaAllocator::computeOrder($limits))->toBe($expected);
})->with([
    'brief 1' => [[5, 5, 10, 20], 20],
    'brief 2' => [array_merge(array_fill(0, 15, 5), [10]), 29], // 15×5+10 → Σ85, наиб10, ceil(85/3)=29
    'brief 3' => [[15, 15, 15], 15],
    'brief 4' => [[15, 15, 15, 30], 30],
    'brief 5' => [[10, 10, 10, 10], 14],
    'single' => [[7], 7],
    'empty' => [[], 0],
]);

// distributeForPlatform: split the group order across N supplier platforms so the
// SUM of per-platform limits == order (portal does NOT divide — verified live 2026-05-21,
// each B1/B2/B3 honors its own limit independently → must split ourselves). Largest-remainder.

it('distributeForPlatform splits order so per-platform limits sum to the order', function (array $platforms, int $order, array $expected): void {
    expect(SupplierQuotaAllocator::distributeForPlatform($order, $platforms))->toBe($expected);
})->with([
    // Even split (the common case — the owner reported 18 → 18/18/18 instead of 6/6/6)
    'call/site 18→6/6/6' => [['B1', 'B2', 'B3'], 18, ['B1' => 6, 'B2' => 6, 'B3' => 6]],
    'call/site 24→8/8/8' => [['B1', 'B2', 'B3'], 24, ['B1' => 8, 'B2' => 8, 'B3' => 8]],
    'call/site 3→1/1/1' => [['B1', 'B2', 'B3'], 3, ['B1' => 1, 'B2' => 1, 'B3' => 1]],
    // Uneven split — largest remainder: leading platforms get the +1, sum stays exact
    'call/site 10→4/3/3' => [['B1', 'B2', 'B3'], 10, ['B1' => 4, 'B2' => 3, 'B3' => 3]],
    'call/site 20→7/7/6' => [['B1', 'B2', 'B3'], 20, ['B1' => 7, 'B2' => 7, 'B3' => 6]],
    // SMS+keyword (2 platforms)
    'sms+kw 5→3/2' => [['B2', 'B3'], 5, ['B2' => 3, 'B3' => 2]],
    'sms+kw 2→1/1' => [['B2', 'B3'], 2, ['B2' => 1, 'B3' => 1]],
    // SMS without keyword (1 platform) — no split, full order
    'sms 7→7' => [['B3'], 7, ['B3' => 7]],
    // Edge: zero order
    'zero' => [['B1', 'B2', 'B3'], 0, ['B1' => 0, 'B2' => 0, 'B3' => 0]],
]);

it('distributeForPlatform always conserves the order (sum invariant)', function (int $order, int $count): void {
    $platforms = array_slice(['B1', 'B2', 'B3'], 0, $count);
    $shares = SupplierQuotaAllocator::distributeForPlatform($order, $platforms);
    expect(array_sum($shares))->toBe($order);
})->with([
    [1, 3], [2, 3], [7, 3], [13, 3], [100, 3], [101, 2], [99, 1], [0, 3],
]);

// Orthogonal smoke tests on allocate() — preserved from pre-T3 coverage; assert
// invariants independent of the order formula (workdays/regions union, null-on-no-eligible).

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

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

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

it('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]],
    ]);

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

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

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

    expect(SupplierQuotaAllocator::allocate('B1', 'site', 'example.com', $projects, Carbon::parse('2026-05-12')))
        ->toBeNull();
});
