<?php

declare(strict_types=1);

namespace Tests\Concerns;

use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;

/**
 * Share PDO between pgsql и pgsql_supplier connections в тестах.
 *
 * Зачем: Laravel DatabaseTransactions trait оборачивает каждый connection в
 * свою транзакцию. Записи через default Project::factory() ($pgsql) не видны
 * с pgsql_supplier connection до commit'а. Sharing PDO означает — обе
 * connection'ы используют ту же PDO session → одну транзакцию.
 *
 * На production обе connection'ы реальные separate PDO, и видимость
 * обеспечивается READ COMMITTED после commit'а webhook-handler'а перед
 * dispatch'ом supplier-flow job'а. Этот trait — только для test-окружения.
 *
 * Использование: `uses(SharesSupplierPdo::class)` в Pest test-файле, где
 * нужна cross-connection visibility (например, tests/Feature/Supplier/*).
 */
trait SharesSupplierPdo
{
    protected function setUpSharesSupplierPdo(): void
    {
        if (! config()->has('database.connections.pgsql_supplier')) {
            return;
        }

        $defaultConnection = DB::connection('pgsql');
        $supplierConnection = DB::connection('pgsql_supplier');
        $supplierConnection->setPdo($defaultConnection->getPdo());
        $supplierConnection->setReadPdo($defaultConnection->getReadPdo());

        // Шарим не только PDO, но и уровень вложенности транзакции. DatabaseTransactions
        // уже открыл транзакцию на pgsql (этот же PDO) к моменту setUp этого трейта.
        // Без синхронизации supplier-connection считает transactions=0 и при
        // DB::connection('pgsql_supplier')->transaction() зовёт PDO->beginTransaction()
        // на уже активной транзакции → PDOException "There is already an active transaction"
        // (например AdminIncidentsController::notifyRkn). С синхронизацией вложенный
        // transaction() делает SAVEPOINT внутри внешней транзакции (Postgres поддерживает),
        // запись видна последующим чтениям и откатывается общим rollback'ом в teardown.
        $level = $defaultConnection->transactionLevel();
        if ($level > 0) {
            $prop = new \ReflectionProperty(Connection::class, 'transactions');
            $prop->setAccessible(true);
            $prop->setValue($supplierConnection, $level);
        }
    }
}
