<?php

use App\Models\Project;
use App\Models\SupplierProject;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\SharesAdminPdo;
use Tests\TestCase;

/*
|--------------------------------------------------------------------------
| Test Case
|--------------------------------------------------------------------------
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
| need to change it using the "pest()" function to bind different classes or traits.
|
*/

pest()->extend(TestCase::class)
 // ->use(RefreshDatabase::class)
    ->in('Feature');

// admin-db middleware swaps default→pgsql_admin; share PDO для cross-connection
// visibility в admin-тестах (любой /api/admin/* эндпоинт). Глобально по Feature.
uses(SharesAdminPdo::class)->in('Feature');

pest()->extend(TestCase::class)->in('Browser');

/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
|
| When you're writing tests, you often need to check that values meet certain conditions. The
| "expect()" function gives you access to a set of "expectations" methods that you can use
| to assert different things. Of course, you may extend the Expectation API at any time.
|
*/

expect()->extend('toBeOne', function () {
    return $this->toBe(1);
});

/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/

function something()
{
    // ..
}

/**
 * Link a Лидерра-project to a supplier_project via the M:N pivot
 * (Plan 1 model). Post-Plan-2 LeadRouter eligibility queries the pivot
 * only; legacy supplier_b{1,2,3}_project_id FK is ignored for routing.
 *
 * Single source — replaces previous duplicated declarations in
 * LeadRouterTest.php / RouteSupplierLeadJobTest.php (Plan 2 cleanup).
 * pivot created_at has DEFAULT NOW(); supplier->subject_code may be null.
 */
function linkProjectToSupplier(Project $project, SupplierProject $supplier): void
{
    DB::table('project_supplier_links')->insert([
        'project_id' => $project->id,
        'supplier_project_id' => $supplier->id,
        'platform' => $supplier->platform,
        'subject_code' => $supplier->subject_code,
    ]);
}

/**
 * Pest helper для slepok-routing тестов (Task 2.5).
 *
 * Создаёт строку в `project_routing_snapshots` за активную дату слепка,
 * отражающую "идеальное" состояние live-проекта. Используется тестами,
 * которым нужен только факт «маршрутизация возможна», а не сам snapshot
 * mechanism.
 *
 * Активная дата по умолчанию — сегодняшняя МСК (до 21:00 МСК). Передайте
 * `$date` явно, если тест использует `Carbon::setTestNow` с другой датой.
 *
 * NB: signal_type/signal_identifier берутся ЯВНО из аргументов, а не из
 * `$project->signal_type` — на Windows-native PG факториальный override
 * этого поля не персистится (см. memory project_slepok_protection.md).
 */
/**
 * Pest helper для SyncSupplierProjectsJob тестов (Task 2.9).
 *
 * Вставляет snapshot в `project_routing_snapshots` за активную дату слепка
 * для tomorrow МСК (cron 18:02 МСК ежедневно создаёт slepok на завтра).
 *
 * После Task 2.9 sync-job читает snapshot, не live `projects.is_active` —
 * без снимка проект не попадает в группировку для подачи поставщику.
 */
/**
 * Слепок зеркалит источник проекта (signal_type / signal_identifier / sms_senders /
 * sms_keyword), как прод-джоб SnapshotProjectRoutingJob. Офлайн-батч (Task 2.6) читает
 * источник ИЗ слепка, поэтому фикстуры обязаны его нести — иначе группировка пустеет.
 *
 * Дефолты `false` = «взять из $project». Явная передача (включая null для sms) — проходит как есть.
 *
 * @param  string|false  $signalType  false = взять из $project
 * @param  string|false|null  $signalIdentifier  false = взять из $project
 * @param  array<int, string>|false|null  $smsSenders  false = взять из $project
 * @param  string|false|null  $smsKeyword  false = взять из $project
 */
function insertSnapshotForTomorrow(
    Project $project,
    string|false $signalType = false,
    string|false|null $signalIdentifier = false,
    ?int $dailyLimit = null,
    ?int $deliveryDaysMask = null,
    string $regions = '{}',
    array|false|null $smsSenders = false,
    string|false|null $smsKeyword = false,
): void {
    // ?: 'call' — проект без источника (preflight-фикстуры) не нарушает CHECK signal_type.
    $type = $signalType === false ? ((string) $project->signal_type ?: 'call') : $signalType;
    $identifier = $signalIdentifier === false ? $project->signal_identifier : $signalIdentifier;
    $senders = $smsSenders === false ? $project->sms_senders : $smsSenders;
    $keyword = $smsKeyword === false ? $project->sms_keyword : $smsKeyword;

    $tomorrow = Carbon::tomorrow('Europe/Moscow')->toDateString();
    DB::table('project_routing_snapshots')->insert([
        'snapshot_date' => $tomorrow,
        'project_id' => $project->id,
        'tenant_id' => $project->tenant_id,
        'daily_limit' => $dailyLimit ?? (int) ($project->daily_limit_target ?? 10),
        'delivery_days_mask' => $deliveryDaysMask ?? (int) ($project->delivery_days_mask ?? 127),
        'regions' => $regions,
        'signal_type' => $type,
        'signal_identifier' => $identifier,
        'sms_senders' => $senders === null ? null : json_encode($senders),
        'sms_keyword' => $keyword,
        'expected_volume' => $dailyLimit ?? (int) ($project->daily_limit_target ?? 10),
        'delivered_count' => 0,
        'created_at' => Date::now(),
    ]);
}

function createRoutingSnapshotFromProject(
    Project $project,
    ?string $date = null,
    string $signalType = 'call',
    ?string $signalIdentifier = null,
    ?int $dailyLimit = null,
    string $regions = '{}',
): void {
    DB::table('project_routing_snapshots')->insert([
        'snapshot_date' => $date ?? Carbon::today('Europe/Moscow')->toDateString(),
        'project_id' => $project->id,
        'tenant_id' => $project->tenant_id,
        'daily_limit' => $dailyLimit ?? (int) ($project->effective_daily_limit_today ?? $project->daily_limit_target),
        'delivery_days_mask' => (int) ($project->delivery_days_mask ?? 127),
        'regions' => $regions,
        'signal_type' => $signalType,
        'signal_identifier' => $signalIdentifier,
        'sms_senders' => null,
        'sms_keyword' => null,
        'expected_volume' => $dailyLimit ?? (int) ($project->effective_daily_limit_today ?? $project->daily_limit_target),
        'delivered_count' => 0,
        'created_at' => Date::now(),
    ]);
}
