<?php

declare(strict_types=1);

use App\Jobs\Supplier\CsvReconcileJob;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\SharesSupplierPdo;

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

it('GET /api/admin/supplier-integration/sync-runs returns evening-upload history (Эпик 5)', function (): void {
    DB::connection('pgsql_supplier')->table('supplier_sync_runs')->insert([
        'started_at' => now()->subMinutes(40),
        'finished_at' => now()->subMinutes(2),
        'groups_total' => 180,
        'synced_ok' => 312,
        'manual_queued' => 1,
        'deferred' => 0,
        'failed' => 0,
        'status' => 'partial',
        'created_at' => now()->subMinutes(2),
    ]);

    $response = $this->getJson('/api/admin/supplier-integration/sync-runs');

    $response->assertOk();
    $response->assertJsonStructure([
        'runs' => [['started_at', 'finished_at', 'groups_total', 'synced_ok', 'manual_queued', 'deferred', 'failed', 'status']],
    ]);
    expect($response->json('runs.0.groups_total'))->toBe(180);
    expect($response->json('runs.0.manual_queued'))->toBe(1);
    expect($response->json('runs.0.status'))->toBe('partial');
});

it('GET /api/admin/supplier-integration returns channel health + history', function (): void {
    DB::connection('pgsql_supplier')->table('supplier_csv_reconcile_log')->insert([
        'started_at' => now()->subMinutes(10),
        'finished_at' => now()->subMinutes(9),
        'window_start' => now()->subDay(),
        'window_end' => now(),
        'total_csv_rows' => 100,
        'matched_count' => 98,
        'recovered_count' => 2,
        'drift_ratio' => 0.02,
        'status' => 'ok',
        'created_at' => now()->subMinutes(10),
    ]);

    $response = $this->getJson('/api/admin/supplier-integration');

    $response->assertOk();
    $response->assertJsonStructure([
        'health' => ['last_run_at', 'last_status', 'drift_ratio', 'webhook_state'],
        'history' => [['started_at', 'status', 'total_csv_rows', 'matched_count', 'recovered_count', 'drift_ratio']],
    ]);
    expect($response->json('health.last_status'))->toBe('ok');
    expect($response->json('health.webhook_state'))->toBe('live');
});

it('webhook_state is "down" when last run had drift_alert', function (): void {
    DB::connection('pgsql_supplier')->table('supplier_csv_reconcile_log')->insert([
        'started_at' => now()->subMinutes(5),
        'finished_at' => now()->subMinutes(4),
        'window_start' => now()->subDay(),
        'window_end' => now(),
        'total_csv_rows' => 100,
        'matched_count' => 80,
        'recovered_count' => 20,
        'drift_ratio' => 0.20,
        'status' => 'drift_alert',
        'created_at' => now()->subMinutes(5),
    ]);

    $response = $this->getJson('/api/admin/supplier-integration');

    expect($response->json('health.webhook_state'))->toBe('down');
});

it('POST /api/admin/supplier-integration/reconcile dispatches CsvReconcileJob', function (): void {
    Bus::fake([CsvReconcileJob::class]);

    $response = $this->postJson('/api/admin/supplier-integration/reconcile');

    $response->assertOk();
    $response->assertJson(['dispatched' => true]);
    Bus::assertDispatched(CsvReconcileJob::class, 1);
});

it('returns nulls in health when reconcile log is empty (no run yet)', function (): void {
    // Пустой supplier_csv_reconcile_log — до первой сверки. Контроллер не должен
    // падать на $last === null (property access на null).
    DB::connection('pgsql_supplier')->table('supplier_csv_reconcile_log')->truncate();

    $response = $this->getJson('/api/admin/supplier-integration');

    $response->assertOk();
    expect($response->json('health.last_run_at'))->toBeNull();
    expect($response->json('health.last_status'))->toBeNull();
    expect($response->json('health.drift_ratio'))->toBeNull();
    expect($response->json('health.webhook_state'))->toBe('live');
    expect($response->json('history'))->toBe([]);
});
