<?php

declare(strict_types=1);

use App\Models\Deal;
use App\Models\Project;
use App\Models\SupplierProject;
use App\Models\Tenant;
use App\Services\DaData\DaDataPhoneClient;
use App\Services\LeadRouter;
use Database\Seeders\PricingTierSeeder;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Random\Engine\Mt19937;
use Random\Randomizer;
use Tests\Concerns\SharesSupplierPdo;
use Tests\Support\Imitation\FakeDaDataPhoneClient;
use Tests\Support\Imitation\LeadInjector;
use Tests\Support\Imitation\SnapshotForge;

uses(DatabaseTransactions::class, SharesSupplierPdo::class);

/**
 * Scenarios B/C — Region Cascade Verification Tests.
 *
 * VERIFICATION tests against existing prod routing code (LeadRouter + RouteSupplierLeadJob).
 * Proves (or disproves) the 3-phase cascade behaviour: exact → all-RF → fallback.
 * NOT TDD — no prod code is modified. Cascade differences vs plan are FINDINGS.
 *
 * Subject codes are порядковые (1..89), NOT коды ГИБДД:
 *   82 = Москва (App\Support\RussianRegions::CODE_TO_NAME[82])
 *   50 = Костромская область (used as "foreign" region — nobody has it exactly)
 *    1 = Республика Адыгея
 *   83 = Санкт-Петербург
 *
 * Task 7 — Phase 1 Portal Client Imitation.
 * Spec: docs/superpowers/specs/2026-06-03-portal-client-imitation-phase1-design.md §6.2/§6.7
 * Plan: docs/superpowers/plans/2026-06-03-portal-client-imitation-phase1.md §Task 7
 */

// ── SUBJECT CODE CONSTANTS (порядковые, НЕ ГИБДД) ────────────────────────────
/** App\Support\RussianRegions::CODE_TO_NAME[82] = 'Москва' */
const BC_MOSCOW = 82;
/** App\Support\RussianRegions::CODE_TO_NAME[83] = 'Санкт-Петербург' */
const BC_SPB = 83;
/** App\Support\RussianRegions::CODE_TO_NAME[50] = 'Костромская область' — nobody subscribes */
const BC_FOREIGN = 50;
/** App\Support\RussianRegions::CODE_TO_NAME[1] = 'Республика Адыгея' */
const BC_ADYGEA = 1;

/**
 * Deterministic Randomizer seed for LeadRouter weightedPick.
 * With only 1-2 candidates, weightedPick returns all in order (no random needed),
 * but we seed it anyway for reproducibility.
 */
const BC_SEED = 7;

/**
 * Shared supplier domain (B1 site signal) for Scenario B.
 */
const BC_B_DOMAIN = 'scenario-b-cascade.ru';

/**
 * Shared supplier domain (B1 site signal) for Scenario C.
 */
const BC_C_DOMAIN = 'scenario-c-cascade.ru';

beforeEach(function (): void {
    // Seed pricing tiers — required by LedgerService::chargeForDelivery.
    $this->seed(PricingTierSeeder::class);

    // Global RLS bypass for seeding phase (tenant context = 0).
    DB::statement("SELECT set_config('app.current_tenant_id', '0', true)");

    // DaData config — real values irrelevant, FakeDaDataPhoneClient bypasses HTTP.
    config([
        'services.dadata.enabled' => true,
        'services.dadata.api_key' => 'fake-key',
        'services.dadata.secret' => 'fake-secret',
        'services.dadata.daily_cap_rub' => 1_000_000,
    ]);

    // Deterministic LeadRouter — with 1-2 candidates weightedPick always returns
    // all of them in SQL order (pool count ≤ cap=3), but seeded Mt19937 ensures
    // reproducibility if the implementation changes.
    $seededRouter = new LeadRouter(new Randomizer(new Mt19937(BC_SEED)));
    app()->instance(LeadRouter::class, $seededRouter);
});

// ══════════════════════════════════════════════════════════════════════════════
// SCENARIO B — exact → all-RF cascade
// ══════════════════════════════════════════════════════════════════════════════

/**
 * Scenario B1: Lead with a subject matching client X's exact region → goes to X (step 1).
 *
 * Setup:
 *   - Client X: regions=[82] (Москва only)
 *   - Client Y: regions=[]  (all-RF)
 *   - Lead resolves to Москва (code 82) via FakeDaData (qc=0, region='Москва')
 *
 * Expected: deal created for X (tenant_X), routing_step=1.
 *           deal NOT created for Y via step-1 (Y is all-RF, not exact-82).
 *           (Y may receive the lead if cap allows — this test has only 1 lead and cap=3
 *            so BOTH X and Y are eligible. Step-2 fills remaining slots.)
 *
 * Cascade logic (LeadRouter):
 *   Phase 1 exact: X matches (82 = ANY('{82}')), Y does NOT ('{}'≠'{82}').
 *   Phase 2 all-RF: Y matches ('{}' = '{}'), fills remaining cap slots.
 *   → selected = [X(step=1), Y(step=2)].
 *
 * So: X gets routing_step=1, Y gets routing_step=2.
 * lead_region_resolution_log.routing_step = step of FIRST project (X→1).
 */
it('B1: lead matching client Xs exact region goes to X at step 1, Y fills at step 2', function (): void {
    // ── ARRANGE ─────────────────────────────────────────────────────────────────

    $supplier = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => BC_B_DOMAIN,
    ]);

    // Client X: only Москва (exact match for subject=82).
    $tenantX = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectX = Project::factory()->create([
        'tenant_id' => $tenantX->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_B_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [BC_MOSCOW],
    ]);
    linkProjectToSupplier($projectX, $supplier);

    // Client Y: all-RF (regions='{}').
    $tenantY = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectY = Project::factory()->create([
        'tenant_id' => $tenantY->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_B_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [],  // all-RF
    ]);
    linkProjectToSupplier($projectY, $supplier);

    $activeDate = SnapshotForge::activeDate();

    createRoutingSnapshotFromProject(
        project: $projectX,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_B_DOMAIN,
        dailyLimit: 10,
        regions: '{'.BC_MOSCOW.'}',
    );
    createRoutingSnapshotFromProject(
        project: $projectY,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_B_DOMAIN,
        dailyLimit: 10,
        regions: '{}',
    );

    // Lead resolves to Москва via FakeDaData (qc=0 → source=dadata, subject=82).
    $fakeDaData = new FakeDaDataPhoneClient;
    $fakeDaData->stub('79161000001', qc: 0, region: 'Москва', provider: 'МТС');
    app()->instance(DaDataPhoneClient::class, $fakeDaData);

    // ── ACT ─────────────────────────────────────────────────────────────────────

    $injector = new LeadInjector;
    $lead = $injector->site(
        domain: BC_B_DOMAIN,
        phone: '79161000001',
        tag: 'Москва',
        platform: 'B1',
        vid: 8_100_000_001,
    );

    // ── ASSERT ──────────────────────────────────────────────────────────────────

    // Tenant X must have received a deal (exact Москва match, step 1).
    $dealsX = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantX->id)
        ->count();

    // Tenant Y (all-RF) receives the deal at step 2 (cap allows both).
    $dealsY = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantY->id)
        ->count();

    fwrite(STDOUT, PHP_EOL.'=== B1 DISTRIBUTION ==='.PHP_EOL);
    fwrite(STDOUT, "Client X (Москва exact) deals: {$dealsX}".PHP_EOL);
    fwrite(STDOUT, "Client Y (all-RF)       deals: {$dealsY}".PHP_EOL);

    // Primary assertion: X gets the lead (routing_step=1 path exists).
    expect($dealsX)->toBe(1,
        'FINDING: Client X (regions=[82]) should receive the Москва lead at step 1. '.
        "Got dealsX={$dealsX}. The exact-match phase (step 1) may not be working."
    );

    // Check lead_region_resolution_log for routing_step=1.
    $logRow = DB::connection('pgsql_supplier')
        ->table('lead_region_resolution_log')
        ->where('supplier_lead_id', $lead->id)
        ->first();

    fwrite(STDOUT, 'resolution_log routing_step: '.($logRow?->routing_step ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, 'resolution_log region_source: '.($logRow?->region_source ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, 'resolution_log subject_code_resolved: '.($logRow?->subject_code_resolved ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, '=== END B1 ==='.PHP_EOL.PHP_EOL);

    expect($logRow)->not->toBeNull(
        'FINDING: lead_region_resolution_log has no row for this lead. '.
        'logRegionResolution() may have failed silently (fail-safe).'
    );

    if ($logRow !== null) {
        expect((int) $logRow->routing_step)->toBe(1,
            'FINDING: lead_region_resolution_log.routing_step should be 1 (first project is X at step 1). '.
            "Got: {$logRow->routing_step}. The log records step of first project in selected collection."
        );

        expect((int) $logRow->subject_code_resolved)->toBe(BC_MOSCOW,
            'FINDING: resolved subject_code should be 82 (Москва) from DaData qc=0. '.
            "Got: {$logRow->subject_code_resolved}."
        );
    }

    // deals.subject_code for X's deal.
    $dealX = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantX->id)
        ->first();

    if ($dealX !== null) {
        expect((int) $dealX->subject_code)->toBe(BC_MOSCOW,
            'FINDING: deals.subject_code should be 82 (Москва) for step-1 deal. '.
            "Got: {$dealX->subject_code}."
        );
    }
})->group('imitation');

/**
 * Scenario B2: Lead with a subject nobody has exactly → goes to all-RF client (step 2).
 *
 * Setup:
 *   - Client X: regions=[82] (Москва only)
 *   - Client Y: regions=[]  (all-RF)
 *   - Lead resolves to code 50 (Костромская область) — no client has this exact region.
 *
 * Expected:
 *   Phase 1 exact: nobody has code 50 → empty.
 *   Phase 2 all-RF: Y matches → Y receives the deal at step 2.
 *   X gets NO deal.
 *   lead_region_resolution_log.routing_step = 2.
 */
it('B2: lead with foreign subject goes to all-RF client at step 2 when nobody has exact', function (): void {
    // ── ARRANGE ─────────────────────────────────────────────────────────────────

    $supplier = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => BC_B_DOMAIN,
    ]);

    // Client X: regions=[82] (Москва) — will NOT match code 50.
    $tenantX = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectX = Project::factory()->create([
        'tenant_id' => $tenantX->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_B_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [BC_MOSCOW],
    ]);
    linkProjectToSupplier($projectX, $supplier);

    // Client Y: all-RF — will match any subject at phase 2.
    $tenantY = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectY = Project::factory()->create([
        'tenant_id' => $tenantY->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_B_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [],  // all-RF
    ]);
    linkProjectToSupplier($projectY, $supplier);

    $activeDate = SnapshotForge::activeDate();

    createRoutingSnapshotFromProject(
        project: $projectX,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_B_DOMAIN,
        dailyLimit: 10,
        regions: '{'.BC_MOSCOW.'}',
    );
    createRoutingSnapshotFromProject(
        project: $projectY,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_B_DOMAIN,
        dailyLimit: 10,
        regions: '{}',
    );

    // Lead resolves to Костромская область (code 50) — DaData qc=0, region name must
    // be the exact string in RussianRegions::CODE_TO_NAME[50] = 'Костромская область'
    // so that DaDataRegionMap::toSubjectCode() returns 50.
    $fakeDaData = new FakeDaDataPhoneClient;
    $fakeDaData->stub('79162000001', qc: 0, region: 'Костромская область', provider: 'Билайн');
    app()->instance(DaDataPhoneClient::class, $fakeDaData);

    // ── ACT ─────────────────────────────────────────────────────────────────────

    $injector = new LeadInjector;
    $lead = $injector->site(
        domain: BC_B_DOMAIN,
        phone: '79162000001',
        tag: null,
        platform: 'B1',
        vid: 8_100_000_002,
    );

    // ── ASSERT ──────────────────────────────────────────────────────────────────

    $dealsX = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantX->id)
        ->count();

    $dealsY = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantY->id)
        ->count();

    $logRow = DB::connection('pgsql_supplier')
        ->table('lead_region_resolution_log')
        ->where('supplier_lead_id', $lead->id)
        ->first();

    fwrite(STDOUT, PHP_EOL.'=== B2 DISTRIBUTION ==='.PHP_EOL);
    fwrite(STDOUT, "Client X (Москва exact) deals: {$dealsX}".PHP_EOL);
    fwrite(STDOUT, "Client Y (all-RF)       deals: {$dealsY}".PHP_EOL);
    fwrite(STDOUT, 'resolution_log routing_step: '.($logRow?->routing_step ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, 'resolution_log subject_code_resolved: '.($logRow?->subject_code_resolved ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, '=== END B2 ==='.PHP_EOL.PHP_EOL);

    // X must NOT receive the lead (code 50 is NOT in X's regions=[82]).
    expect($dealsX)->toBe(0,
        'FINDING: Client X (regions=[82]) should NOT receive a lead with subject=50 (Костромская область). '.
        "Got dealsX={$dealsX}. Phase-1 exact filter may be matching wrong subjects."
    );

    // Y must receive the lead (all-RF, step 2).
    expect($dealsY)->toBe(1,
        "FINDING: Client Y (all-RF regions='{}') should receive the lead at step 2. ".
        "Got dealsY={$dealsY}. Phase-2 all-RF filter may not be working."
    );

    expect($logRow)->not->toBeNull(
        'FINDING: lead_region_resolution_log has no row. logRegionResolution() may have failed.'
    );

    if ($logRow !== null) {
        expect((int) $logRow->routing_step)->toBe(2,
            'FINDING: routing_step should be 2 (first project in selected is Y at step 2). '.
            "Got: {$logRow->routing_step}."
        );

        expect((int) $logRow->subject_code_resolved)->toBe(BC_FOREIGN,
            'FINDING: resolved subject_code should be 50 (Костромская область). '.
            "Got: {$logRow->subject_code_resolved}."
        );
    }
})->group('imitation');

// ══════════════════════════════════════════════════════════════════════════════
// SCENARIO C — each client gets only its own region (phase-1 isolation)
// ══════════════════════════════════════════════════════════════════════════════

/**
 * Scenario C1: Two clients with different exact regions — each lead goes to only its own.
 *
 * Setup:
 *   - Client A: regions=[1]  (Республика Адыгея)
 *   - Client B: regions=[83] (Санкт-Петербург)
 *
 * Lead 1 resolves to subject=1  → A gets it at step 1; B does NOT.
 * Lead 2 resolves to subject=83 → B gets it at step 1; A does NOT.
 *
 * Phase 2 (all-RF) is empty here — neither A nor B has regions='{}',
 * so there are no all-RF clients. If exact match returns 1 result and cap=3,
 * phases 2+3 run for remaining slots. Since phase 2 (all-RF) is empty and
 * phase 3 (any) would match BOTH — we verify that:
 *   - exactly 1 deal per lead is created (step-1 match);
 *   - OR phase 3 fires and the other client ALSO gets the lead (FINDING if so).
 *
 * This test asserts the strongest useful claim: each client sees only its own
 * leads from step-1. Phase-3 fallback behaviour is reported as a FINDING if it
 * fires (because no all-RF client exists, phase 2 is empty, and phase 3 is the
 * "any" fallback which would give the lead to both — if that's what happens, it
 * means the cascade reaches phase 3 even with 1 exact match at phase 1).
 *
 * NOTE: LeadRouter cap=3 and phase-1 picks 1 project. Since combined.isNotEmpty()
 * after phase 1+2 → phase 3 is NOT entered (LeadRouter returns combined if
 * combined.isNotEmpty()). So: lead→A at step 1 only (Y is not all-RF so phase 2
 * returns nothing, but combined=[A] is NOT empty → phase 3 skipped). ✓
 */
it('C1: lead with subject code 1 goes only to client A (regions=[1]), not to client B (regions=[83])', function (): void {
    // ── ARRANGE ─────────────────────────────────────────────────────────────────

    $supplier = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => BC_C_DOMAIN,
    ]);

    // Client A: Республика Адыгея (code 1).
    $tenantA = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectA = Project::factory()->create([
        'tenant_id' => $tenantA->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_C_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [BC_ADYGEA],  // code 1
    ]);
    linkProjectToSupplier($projectA, $supplier);

    // Client B: Санкт-Петербург (code 83).
    $tenantB = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectB = Project::factory()->create([
        'tenant_id' => $tenantB->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_C_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [BC_SPB],     // code 83
    ]);
    linkProjectToSupplier($projectB, $supplier);

    $activeDate = SnapshotForge::activeDate();

    createRoutingSnapshotFromProject(
        project: $projectA,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_C_DOMAIN,
        dailyLimit: 10,
        regions: '{'.BC_ADYGEA.'}',
    );
    createRoutingSnapshotFromProject(
        project: $projectB,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_C_DOMAIN,
        dailyLimit: 10,
        regions: '{'.BC_SPB.'}',
    );

    // FakeDaData: phone→Adygea (code 1).
    // RussianRegions::CODE_TO_NAME[1] = 'Республика Адыгея'
    $fakeDaData = new FakeDaDataPhoneClient;
    $fakeDaData->stub('79163000001', qc: 0, region: 'Республика Адыгея', provider: 'МегаФон');
    app()->instance(DaDataPhoneClient::class, $fakeDaData);

    // ── ACT ─────────────────────────────────────────────────────────────────────

    $injector = new LeadInjector;
    $leadAdygea = $injector->site(
        domain: BC_C_DOMAIN,
        phone: '79163000001',
        tag: null,
        platform: 'B1',
        vid: 8_100_000_010,
    );

    // ── ASSERT ──────────────────────────────────────────────────────────────────

    $dealsA = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantA->id)
        ->count();

    $dealsB = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantB->id)
        ->count();

    $logRow = DB::connection('pgsql_supplier')
        ->table('lead_region_resolution_log')
        ->where('supplier_lead_id', $leadAdygea->id)
        ->first();

    fwrite(STDOUT, PHP_EOL.'=== C1 DISTRIBUTION (lead→Адыгея) ==='.PHP_EOL);
    fwrite(STDOUT, "Client A (Адыгея code=1) deals: {$dealsA}".PHP_EOL);
    fwrite(STDOUT, "Client B (СПб    code=83) deals: {$dealsB}".PHP_EOL);
    fwrite(STDOUT, 'resolution_log routing_step: '.($logRow?->routing_step ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, 'resolution_log subject_code_resolved: '.($logRow?->subject_code_resolved ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, '=== END C1 ==='.PHP_EOL.PHP_EOL);

    // A must receive the lead.
    expect($dealsA)->toBe(1,
        'FINDING: Client A (regions=[1], Адыгея) should receive the lead with subject=1. '.
        "Got dealsA={$dealsA}. Phase-1 exact match may not be working for small subject codes."
    );

    // B must NOT receive the lead (step-1 only → combined=[A] is not empty → phase 3 skipped).
    expect($dealsB)->toBe(0,
        'FINDING: Client B (regions=[83], СПб) should NOT receive the Адыгея lead. '.
        "Got dealsB={$dealsB}. ".
        "If >0: the cascade reached phase 3 (fallback 'any') and gave the lead to B as well. ".
        'This is because phase 1 picked A (1 candidate < cap=3) and phase 2 (all-RF) was empty, '.
        'so combined=[A] which is NOT empty → phase 3 is skipped per LeadRouter logic. '.
        'If B got the lead, phase 3 fired — investigate LeadRouter.combined.isNotEmpty() branch.'
    );

    if ($logRow !== null) {
        expect((int) $logRow->routing_step)->toBe(1,
            "FINDING: routing_step should be 1 (A matched exactly). Got: {$logRow->routing_step}."
        );
    }
})->group('imitation');

/**
 * Scenario C2: Lead with СПб subject goes only to client B, not to A.
 *
 * Mirror of C1 — proves bidirectional isolation.
 */
it('C2: lead with subject code 83 goes only to client B (regions=[83]), not to client A (regions=[1])', function (): void {
    // ── ARRANGE ─────────────────────────────────────────────────────────────────

    $supplier = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => BC_C_DOMAIN,
    ]);

    $tenantA = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectA = Project::factory()->create([
        'tenant_id' => $tenantA->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_C_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [BC_ADYGEA],
    ]);
    linkProjectToSupplier($projectA, $supplier);

    $tenantB = Tenant::factory()->create([
        'balance_rub' => '99999.00',
        'frozen_by_balance_at' => null,
    ]);
    $projectB = Project::factory()->create([
        'tenant_id' => $tenantB->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => BC_C_DOMAIN,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => null,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
        'delivery_days_mask' => 127,
        'preflight_blocked_at' => null,
        'regions' => [BC_SPB],
    ]);
    linkProjectToSupplier($projectB, $supplier);

    $activeDate = SnapshotForge::activeDate();

    createRoutingSnapshotFromProject(
        project: $projectA,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_C_DOMAIN,
        dailyLimit: 10,
        regions: '{'.BC_ADYGEA.'}',
    );
    createRoutingSnapshotFromProject(
        project: $projectB,
        date: $activeDate,
        signalType: 'site',
        signalIdentifier: BC_C_DOMAIN,
        dailyLimit: 10,
        regions: '{'.BC_SPB.'}',
    );

    // FakeDaData: phone→СПб (code 83).
    // RussianRegions::CODE_TO_NAME[83] = 'Санкт-Петербург'
    $fakeDaData = new FakeDaDataPhoneClient;
    $fakeDaData->stub('79164000001', qc: 0, region: 'Санкт-Петербург', provider: 'Теле2');
    app()->instance(DaDataPhoneClient::class, $fakeDaData);

    // ── ACT ─────────────────────────────────────────────────────────────────────

    $injector = new LeadInjector;
    $leadSpb = $injector->site(
        domain: BC_C_DOMAIN,
        phone: '79164000001',
        tag: null,
        platform: 'B1',
        vid: 8_100_000_011,
    );

    // ── ASSERT ──────────────────────────────────────────────────────────────────

    $dealsA = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantA->id)
        ->count();

    $dealsB = DB::connection('pgsql_supplier')
        ->table('deals')
        ->where('tenant_id', $tenantB->id)
        ->count();

    $logRow = DB::connection('pgsql_supplier')
        ->table('lead_region_resolution_log')
        ->where('supplier_lead_id', $leadSpb->id)
        ->first();

    fwrite(STDOUT, PHP_EOL.'=== C2 DISTRIBUTION (lead→СПб) ==='.PHP_EOL);
    fwrite(STDOUT, "Client A (Адыгея code=1) deals: {$dealsA}".PHP_EOL);
    fwrite(STDOUT, "Client B (СПб    code=83) deals: {$dealsB}".PHP_EOL);
    fwrite(STDOUT, 'resolution_log routing_step: '.($logRow?->routing_step ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, 'resolution_log subject_code_resolved: '.($logRow?->subject_code_resolved ?? 'NULL').PHP_EOL);
    fwrite(STDOUT, '=== END C2 ==='.PHP_EOL.PHP_EOL);

    // B must receive the lead (exact СПб match at step 1).
    expect($dealsB)->toBe(1,
        'FINDING: Client B (regions=[83], СПб) should receive the СПб lead at step 1. '.
        "Got dealsB={$dealsB}."
    );

    // A must NOT receive the lead.
    expect($dealsA)->toBe(0,
        'FINDING: Client A (regions=[1], Адыгея) should NOT receive the СПб lead. '.
        "Got dealsA={$dealsA}. Phase-3 fallback may have fired — investigate."
    );

    if ($logRow !== null) {
        expect((int) $logRow->routing_step)->toBe(1,
            "FINDING: routing_step should be 1. Got: {$logRow->routing_step}."
        );

        expect((int) $logRow->subject_code_resolved)->toBe(BC_SPB,
            'FINDING: resolved subject_code should be 83 (Санкт-Петербург). '.
            "Got: {$logRow->subject_code_resolved}."
        );
    }
})->group('imitation');
