<?php

declare(strict_types=1);

use App\Models\Project;
use App\Models\Tenant;
use App\Services\SupplierResolver;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

/**
 * Unit-тесты SupplierResolver — вынесенный сервис из ProcessWebhookJob /
 * DealController (Ю-2 / §20.12.3).
 *
 * Контракт:
 *   - resolveForProject() возвращает первого активного supplier'а
 *     по (project_suppliers.is_active=true, suppliers.is_active=true)
 *     ORDER BY suppliers.sort_order, suppliers.id; иначе null.
 *   - costRubSnapshot() возвращает текущий cost_rub поставщика как string
 *     (Decimal cast в Eloquent — но мы ходим через DB::table).
 */
uses(DatabaseTransactions::class);

function seedSupplier(string $code, float $costRub, bool $isActive, int $sortOrder = 0): int
{
    return (int) DB::table('suppliers')->insertGetId([
        'code' => $code.'-'.Str::lower(Str::random(4)),
        'name' => 'Test '.$code,
        'accepts_types' => '{websites,calls}',
        'cost_rub' => $costRub,
        'channel' => 'sites',
        'quality_score' => 1.00,
        'is_active' => $isActive,
        'sort_order' => $sortOrder,
    ]);
}

function attachSupplier(Project $project, int $supplierId, bool $isActive = true): void
{
    DB::table('project_suppliers')->insert([
        'project_id' => $project->id,
        'supplier_id' => $supplierId,
        'is_active' => $isActive,
        'created_at' => now(),
    ]);
}

beforeEach(function () {
    $this->tenant = Tenant::factory()->create();
    $this->project = Project::factory()->for($this->tenant)->create([
        'name' => 'Test Project',
        'type' => 'webhook',
    ]);
    $this->resolver = new SupplierResolver;
});

test('resolveForProject возвращает null когда у проекта нет связей', function () {
    expect($this->resolver->resolveForProject($this->project))->toBeNull();
});

test('resolveForProject возвращает supplier_id единственного активного поставщика', function () {
    $supplierId = seedSupplier('one', 50.00, isActive: true);
    attachSupplier($this->project, $supplierId);

    expect($this->resolver->resolveForProject($this->project))->toBe($supplierId);
});

test('resolveForProject пропускает inactive supplier', function () {
    $inactive = seedSupplier('inactive', 50.00, isActive: false);
    $active = seedSupplier('active', 75.00, isActive: true);
    attachSupplier($this->project, $inactive);
    attachSupplier($this->project, $active);

    expect($this->resolver->resolveForProject($this->project))->toBe($active);
});

test('resolveForProject пропускает inactive m2m-связь', function () {
    $a = seedSupplier('a', 50.00, isActive: true);
    $b = seedSupplier('b', 75.00, isActive: true);
    attachSupplier($this->project, $a, isActive: false);
    attachSupplier($this->project, $b, isActive: true);

    expect($this->resolver->resolveForProject($this->project))->toBe($b);
});

test('resolveForProject соблюдает ORDER BY sort_order, id', function () {
    $second = seedSupplier('second', 100.00, isActive: true, sortOrder: 10);
    $first = seedSupplier('first', 200.00, isActive: true, sortOrder: 1);
    $third = seedSupplier('third', 50.00, isActive: true, sortOrder: 100);
    attachSupplier($this->project, $second);
    attachSupplier($this->project, $first);
    attachSupplier($this->project, $third);

    expect($this->resolver->resolveForProject($this->project))->toBe($first);
});

test('resolveForProject возвращает null если все связи inactive', function () {
    $a = seedSupplier('a', 50.00, isActive: true);
    $b = seedSupplier('b', 75.00, isActive: true);
    attachSupplier($this->project, $a, isActive: false);
    attachSupplier($this->project, $b, isActive: false);

    expect($this->resolver->resolveForProject($this->project))->toBeNull();
});

test('resolveForProject изолирован по project_id', function () {
    $supplierId = seedSupplier('shared', 50.00, isActive: true);
    attachSupplier($this->project, $supplierId);

    $otherProject = Project::factory()->for($this->tenant)->create();

    expect($this->resolver->resolveForProject($this->project))->toBe($supplierId);
    expect($this->resolver->resolveForProject($otherProject))->toBeNull();
});

test('costRubSnapshot возвращает текущую цену поставщика', function () {
    $supplierId = seedSupplier('priced', 137.50, isActive: true);

    expect($this->resolver->costRubSnapshot($supplierId))->toBe('137.50');
});
