<?php

declare(strict_types=1);

use App\Models\Project;
use App\Models\Tenant;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\SharesSupplierPdo;

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

beforeEach(function () {
    DB::statement("SELECT set_config('app.current_tenant_id', '0', true)");
});

it('resets tenants.delivered_in_month and projects.delivered_in_month to 0', function () {
    $tenantA = Tenant::factory()->create(['delivered_in_month' => 100]);
    $tenantB = Tenant::factory()->create(['delivered_in_month' => 5]);
    $tenantC = Tenant::factory()->create(['delivered_in_month' => 0]);

    Project::factory()->create(['tenant_id' => $tenantA->id, 'delivered_in_month' => 50]);
    Project::factory()->create(['tenant_id' => $tenantA->id, 'delivered_in_month' => 50]);
    Project::factory()->create(['tenant_id' => $tenantB->id, 'delivered_in_month' => 5]);

    Artisan::call('projects:reset-monthly');

    expect($tenantA->fresh()->delivered_in_month)->toBe(0);
    expect($tenantB->fresh()->delivered_in_month)->toBe(0);
    expect($tenantC->fresh()->delivered_in_month)->toBe(0);

    expect(Project::sum('delivered_in_month'))->toBe(0);
});

it('is idempotent — second run reports 0 affected', function () {
    $tenant = Tenant::factory()->create(['delivered_in_month' => 10]);
    Project::factory()->create(['tenant_id' => $tenant->id, 'delivered_in_month' => 10]);

    // Первый прогон сбрасывает оба счётчика.
    Artisan::call('projects:reset-monthly');

    // Второй прогон должен сообщить о 0 затронутых строках (WHERE delivered_in_month <> 0).
    // info() пишет ОДНУ строку «Monthly reset: 0 tenants, 0 projects.» —
    // expectsOutputToContain в Laravel 13 line-by-line, поэтому проверяем
    // обе подстроки одним substring'ом.
    $this->artisan('projects:reset-monthly')
        ->expectsOutputToContain('0 tenants, 0 projects')
        ->assertExitCode(0);
});

it('Schedule entry registered for monthly on 1st 00:00 Europe/Moscow', function () {
    /** @var Schedule $schedule */
    $schedule = app(Schedule::class);

    $found = collect($schedule->events())->first(
        fn ($event) => str_contains($event->command ?? '', 'projects:reset-monthly')
    );

    expect($found)->not->toBeNull();
    expect($found->expression)->toBe('0 0 1 * *');
    expect($found->timezone)->toBe('Europe/Moscow');
});

it('uses pgsql_supplier BYPASSRLS connection (touches all tenants without SET LOCAL)', function () {
    Tenant::factory()->count(3)->create(['delivered_in_month' => 7]);

    // Без SET LOCAL app.current_tenant_id reset должен затронуть всех 3 tenant'ов.
    // Это тест на использование pgsql_supplier (BYPASSRLS), не default pgsql.
    Artisan::call('projects:reset-monthly');

    expect(Tenant::where('delivered_in_month', '>', 0)->count())->toBe(0);
});
