<?php

namespace Tests;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Event;
use Stancl\Tenancy\Events\TenantCreated;

/**
 * Unified test case for all database scenarios.
 *
 * Configuration (override in test class):
 *
 * Database options:
 *   $needsMasterDatabase = true|false (default: true)
 *   $needsTenantDatabase = true|false (default: true)
 *
 * Tenancy options (auto-configured based on needsMasterDatabase):
 *   $useRealTenant = true|false (auto: true if master DB, false otherwise)
 *   $fakeTenantTier, $fakeTenantDomain, $fakeTenantFeatures
 *
 * Mock options (only for tenant-only tests):
 *   $useTestSettingRepository = true|false (default: true)
 *   $mockCountryFacade = true|false (default: false)
 *
 * Middleware options:
 *   $withoutMiddlewares = true|false (for master+tenant tests)
 *   Note: Tenant-only tests auto-disable middlewares
 */
abstract class DatabaseTestCase extends BaseTestCase
{
    use CreatesApplication;
    use DispatchesJobs;
    use UsesDatabase;
    use UsesTenancy;

    protected bool $withoutMiddlewares = false;

    protected function setUp(): void
    {
        parent::setUp();

        $this->autoConfigureTenancy();
        $this->fakeEvents();

        $this->setUpDatabases();
        $this->initializeTenancy();

        if ($this->withoutMiddlewares && $this->useRealTenant) {
            $this->withoutMiddleware();
        }
    }

    /**
     * Auto-configure tenancy mode based on database configuration.
     * Master DB present → real tenant; No master DB → fake tenant
     */
    private function autoConfigureTenancy(): void
    {
        $this->useRealTenant = $this->needsMasterDatabase;
    }

    private function fakeEvents(): void
    {
        // Prevent TenantCreated from creating actual databases
        Event::fake([TenantCreated::class]);
    }

    protected function tearDown(): void
    {
        $this->tearDownDatabase();
        parent::tearDown();
        gc_collect_cycles();
    }
}
