<?php

namespace Tests;

use App\Newsletter\CampaignMonitor;
use App\Newsletter\MailChimp;
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
 *
 * Mock options (only for tenant-only tests):
 *   $useTestSettingRepository = true|false (default: true)
 */
abstract class DatabaseTestCase extends BaseTestCase
{
    use CreatesApplication;
    use DispatchesJobs;
    use UsesDatabase;
    use UsesTenancy;

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

        $this->app->bind(MailChimp::class, fn () => new MailChimp(new FakeMailchimp('test-api-key')));

        $this->app->bind(
            CampaignMonitor::class,
            fn () => new CampaignMonitor(new FakeCampaignMonitor('list-id', ['api_key' => 'test-api-key']))
        );

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

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

    /**
     * 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 asTenant($tenant): static
    {
        $this->withHeader('X-Tenant', 'demo.com');
        return $this;
    }

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