<?php

declare(strict_types=1);

use App\Models\Deal;
use App\Models\Tenant;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

// NOTE: \Tests\TestCase auto-binds via tests/Pest.php (->in('Feature')); explicit
// uses(\Tests\TestCase::class) conflicts ("already uses the test case").
// DatabaseTransactions — изоляция: каждый тест выполняется в транзакции, rollback после.
// Project convention: LeadChargeTest / PricingTierTest используют тот же паттерн.
uses(DatabaseTransactions::class);

it('tenants table has delivered_in_month column with CHECK >= 0', function () {
    expect(Schema::hasColumn('tenants', 'delivered_in_month'))->toBeTrue();
    DB::table('tenants')->where('id', '<', 0)->update(['delivered_in_month' => 5]); // no-op
    expect(fn () => DB::statement(
        'INSERT INTO tenants (subdomain, organization_name, contact_email, delivered_in_month) '.
        "VALUES ('t-neg-test', 'X', 'x@x', -1)"
    ))->toThrow(QueryException::class);
});

it('lead_charges table has charge_source column with CHECK on prepaid=zero-price', function () {
    expect(Schema::hasColumn('lead_charges', 'charge_source'))->toBeTrue();
    $tenant = Tenant::factory()->create();
    $deal = Deal::factory()->create(['tenant_id' => $tenant->id]);
    expect(fn () => DB::table('lead_charges')->insert([
        'tenant_id' => $tenant->id,
        'deal_id' => $deal->id,
        'deal_received_at' => $deal->received_at,
        'tier_no' => 1,
        'price_per_lead_kopecks' => 50000,
        'charge_source' => 'prepaid',
        'charged_at' => now(),
        'created_at' => now(),
    ]))->toThrow(QueryException::class);
});

it('supplier_leads table has recovered_from_csv_at column', function () {
    expect(Schema::hasColumn('supplier_leads', 'recovered_from_csv_at'))->toBeTrue();
});

it('supplier_csv_reconcile_log table exists with required columns and status CHECK', function () {
    expect(Schema::hasTable('supplier_csv_reconcile_log'))->toBeTrue();
    expect(Schema::hasColumns('supplier_csv_reconcile_log', [
        'id', 'started_at', 'finished_at', 'window_start', 'window_end',
        'total_csv_rows', 'matched_count', 'recovered_count', 'drift_ratio',
        'status', 'error_message', 'alert_email_sent_at', 'created_at',
    ]))->toBeTrue();
    expect(fn () => DB::table('supplier_csv_reconcile_log')->insert([
        'started_at' => now(),
        'window_start' => now()->subDay(),
        'window_end' => now(),
        'status' => 'unknown_status',
    ]))->toThrow(QueryException::class);
});

it('schema.sql v8.55 has correct metrics — 74 base tables, 128 indexes, 44 RLS policies', function () {
    // Замена destructive `migrate:fresh` (cross-test coupling: после DROP CASCADE остальные
    // Feature-тесты в той же сессии видели пустую БД). Static parse `db/schema.sql` —
    // источник истины метрик.
    // v8.21 (Sprint 4): +1 таблица import_unknown_statuses, +1 индекс, +1 RLS-политика.
    // v8.22 (Plan 6/C9): +1 GIN-индекс idx_projects_regions.
    // v8.25 (supplier-failover): +1 таблица supplier_manual_sync_queue, +2 индекса.
    // v8.26 (project-migration-redesign Plans 1-3): +1 таблица project_supplier_links (M:N pivot)
    //   + 2 индекса (supplier_projects_platform_key_subject_unique, idx_psl_*).
    // v8.30: +1 таблица scheduler_heartbeats (SaaS-level, hole #6).
    // v8.31: 7 audit-таблиц переведены в PARTITION BY RANGE, hole #2.
    // v8.35 (legacy webhook removal): −2 таблицы (webhook_log partitioned + rejected_deals_log)
    //   −5 индексов, −2 RLS-политики, −2 колонки tenants.webhook_token/webhook_token_rotated_at.
    // v8.36→v8.52: рост схемы (lead-region phone_ranges/lead_region_resolution_log,
    //   project_routing_snapshots, tenant_requisites, support_requests и др.).
    // v8.54 (Эпик 4 online-defer): +1 таблица supplier_deferred_sync (SaaS-level, PK неявный, +0 явных индексов).
    // v8.55 (Эпик 5 отчёт заливки): +1 таблица supplier_sync_runs + 1 индекс idx_supplier_sync_runs_created.
    //   Статический парс db/schema.sql после v8.54/v8.55: 74 base tables, 128 индексов, 44 RLS-политики.
    //   NB: бегущий счётчик в ШАПКЕ schema.sql несёт исторический дрейф (заявляет 79 таблиц/124 индекса) —
    //   это отдельный canon-sync, не предмет этого теста; тест сверяет фактический парс ФАЙЛА.
    $schemaPath = dirname(base_path()).DIRECTORY_SEPARATOR.'db'.DIRECTORY_SEPARATOR.'schema.sql';
    expect(is_file($schemaPath) && is_readable($schemaPath))->toBeTrue();
    $schema = file_get_contents($schemaPath);
    expect($schema)->not->toBeFalse();

    // 66 base tables = все CREATE TABLE минус PARTITION OF.
    $createTables = preg_match_all('/^CREATE TABLE\b/m', $schema);
    $partitionOf = preg_match_all('/CREATE TABLE\s+\w+\s+PARTITION OF\b/m', $schema);
    $baseTables = $createTables - $partitionOf;
    expect($baseTables)->toBe(74);

    $createIndexes = preg_match_all('/^CREATE\s+(?:UNIQUE\s+)?INDEX\b/m', $schema);
    expect($createIndexes)->toBe(128);  // v8.55 static parse

    $createPolicies = preg_match_all('/^CREATE\s+POLICY\b/m', $schema);
    expect($createPolicies)->toBe(44);  // v8.52 static parse
});
