<?php

declare(strict_types=1);

namespace Tests\Concerns;

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

/**
 * Share PDO между pgsql и pgsql_admin connections в тестах.
 *
 * Зачем: middleware UseAdminConnection (alias admin-db) на группе saas-admin
 * переключает default-подключение на pgsql_admin (роль crm_admin_user). В тестах
 * DatabaseTransactions оборачивает каждый connection в свою транзакцию: данные,
 * засеянные через default Tenant::factory() ($pgsql), не видны с pgsql_admin
 * connection до commit'а → admin-эндпоинты в тестах видят 0 строк / 404.
 * Sharing PDO означает — обе connection используют ту же PDO session → одну
 * транзакцию, и засеянные данные видны admin-контроллеру.
 *
 * На production обе connection реальные separate PDO; pgsql_admin (srv_bypass)
 * видит все тенанты по READ COMMITTED. Этот trait — только для test-окружения.
 *
 * Зеркало [[SharesSupplierPdo]] для pgsql_admin. Применяется глобально к Feature
 * suite (см. tests/Pest.php), т.к. admin-db висит на всей группе saas-admin —
 * любой admin-тест (текущий и будущий) получает cross-connection visibility без
 * per-file opt-in. Для не-admin тестов инертен (pgsql_admin просто не запрашивают).
 */
trait SharesAdminPdo
{
    protected function setUpSharesAdminPdo(): void
    {
        if (! config()->has('database.connections.pgsql_admin')) {
            return;
        }

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

        // Синхронизируем уровень вложенности транзакции: DatabaseTransactions уже
        // открыл транзакцию на pgsql (тот же PDO) к моменту setUp. Без синхронизации
        // pgsql_admin считает transactions=0 и при ->transaction() зовёт
        // PDO->beginTransaction() на уже активной транзакции → PDOException
        // "There is already an active transaction" (например AdminTenantsController::
        // updateBalance). С синхронизацией вложенный transaction() делает SAVEPOINT.
        $level = $defaultConnection->transactionLevel();
        if ($level > 0) {
            $prop = new \ReflectionProperty(Connection::class, 'transactions');
            $prop->setAccessible(true);
            $prop->setValue($adminConnection, $level);
        }
    }
}
