<?php

declare(strict_types=1);

use App\Jobs\RouteSupplierLeadJob;
use App\Models\Project;
use App\Models\SupplierLead;
use App\Models\SupplierProject;
use App\Models\Tenant;
use App\Services\Billing\LedgerService;
use App\Services\LeadDistributor;
use App\Services\LeadRouter;
use App\Services\MonthlyPartitionManager;
use App\Services\NotificationService;
use App\Services\RegionTagResolver;
use App\Services\SupplierProjects\SupplierProjectResolver;
use Carbon\Carbon;
use Database\Seeders\PricingTierSeeder;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\SharesSupplierPdo;

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

beforeEach(function (): void {
    $this->seed(PricingTierSeeder::class);
    DB::statement("SELECT set_config('app.current_tenant_id', '0', true)");
    // Тесты фиксируют Carbon на 2026-05-28; доставка пишет в несколько
    // партиционированных таблиц (deals/balance_transactions/activity_log/
    // pd_processing_log/tenant_operations_log) → гарантируем партиции мая для всех.
    $mpm = app(MonthlyPartitionManager::class);
    foreach (array_keys(MonthlyPartitionManager::PARTITIONED_TABLES) as $table) {
        $mpm->ensureRange($table, Carbon::parse('2026-05-01'), Carbon::parse('2026-05-31'));
    }
});

function runSnapshotRouteJob(int $supplierLeadId): void
{
    (new RouteSupplierLeadJob($supplierLeadId))->handle(
        app(LeadRouter::class),
        app(SupplierProjectResolver::class),
        app(NotificationService::class),
        app(LedgerService::class),
        app(LeadDistributor::class),
        app(RegionTagResolver::class),
    );
}

it('uses snapshot daily_limit, not live daily_limit_target (R-04/R-06)', function (): void {
    Carbon::setTestNow('2026-05-28 12:00:00', 'Europe/Moscow');

    $tenant = Tenant::factory()->create(['balance_rub' => '500.00', 'frozen_by_balance_at' => null]);
    $project = Project::factory()->for($tenant)->create([
        'is_active' => true,
        'delivery_days_mask' => 127,
        'daily_limit_target' => 100, // live limit big
        'delivered_today' => 4,
        'delivered_in_month' => 0,
    ]);
    $sp = SupplierProject::factory()->create(['signal_type' => 'site']);
    linkProjectToSupplier($project, $sp);
    // Snapshot имеет МАЛЕНЬКИЙ daily_limit=5 — после доставки 1 deal'a должно стать 5.
    createRoutingSnapshotFromProject(
        $project,
        date: '2026-05-28',
        signalType: 'site',
        signalIdentifier: $sp->unique_key,
        dailyLimit: 5,
    );

    $lead = SupplierLead::factory()->create([
        'supplier_project_id' => $sp->id,
        'raw_payload' => ['project' => $sp->platform.'_'.$sp->unique_key, 'phones' => ['79161234567']],
        'phone' => '79161234567',
        'vid' => 1001,
    ]);

    runSnapshotRouteJob($lead->id);

    expect(DB::table('deals')->where('tenant_id', $tenant->id)->count())->toBe(1);

    // delivered_today инкрементнут на live, delivered_count на snapshot.
    expect((int) DB::table('projects')->where('id', $project->id)->value('delivered_today'))->toBe(5);

    $snap = DB::table('project_routing_snapshots')
        ->where('snapshot_date', '2026-05-28')
        ->where('project_id', $project->id)
        ->first();
    expect((int) $snap->delivered_count)->toBe(1);

    Carbon::setTestNow();
});

it('rejects lead when is_active becomes false under lock (R-09)', function (): void {
    Carbon::setTestNow('2026-05-28 12:00:00', 'Europe/Moscow');

    $tenant = Tenant::factory()->create(['balance_rub' => '500.00', 'frozen_by_balance_at' => null]);
    // Live state: is_active=true для snapshot:backfill, но потом клиент нажмёт «пауза»
    // (между matchEligibleProjects и handle). Имитируем это inline UPDATE'ом.
    $project = Project::factory()->for($tenant)->create([
        'is_active' => true,
        'delivery_days_mask' => 127,
        'daily_limit_target' => 10,
        'delivered_today' => 0,
        'delivered_in_month' => 0,
    ]);
    $sp = SupplierProject::factory()->create(['signal_type' => 'site']);
    linkProjectToSupplier($project, $sp);
    // Snapshot НЕ paused (fixed до момента pause'а).
    createRoutingSnapshotFromProject(
        $project,
        date: '2026-05-28',
        signalType: 'site',
        signalIdentifier: $sp->unique_key,
        dailyLimit: 10,
    );

    // ↓ Имитация: клиент paused проект в окне между matchEligible и handle.
    DB::table('projects')->where('id', $project->id)->update(['is_active' => false]);

    $lead = SupplierLead::factory()->create([
        'supplier_project_id' => $sp->id,
        'raw_payload' => ['project' => $sp->platform.'_'.$sp->unique_key, 'phones' => ['79161234567']],
        'phone' => '79161234567',
        'vid' => 1002,
    ]);

    runSnapshotRouteJob($lead->id);

    // Snapshot говорит «доставлять», но live is_active=false под lock'ом — НЕ доставляем.
    expect(DB::table('deals')->where('tenant_id', $tenant->id)->count())->toBe(0);
    expect((int) DB::table('projects')->where('id', $project->id)->value('delivered_today'))->toBe(0);

    $snap = DB::table('project_routing_snapshots')
        ->where('snapshot_date', '2026-05-28')
        ->where('project_id', $project->id)
        ->first();
    expect((int) $snap->delivered_count)->toBe(0);

    Carbon::setTestNow();
});
