<?php

namespace Tests\Feature;

use App\Models\AllowedAdAccount;
use App\Services\Meta\MetaException;
use App\Services\Platforms\Support\Guardrails;
use Database\Seeders\AllowedAdAccountSeeder;
use Illuminate\Database\UniqueConstraintViolationException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AllowedAdAccountDatabaseTest extends TestCase
{
    use RefreshDatabase;

    private Guardrails $guardrails;

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

        // Clear config to test pure database authorization
        config(['platforms.guardrails.allowed_ad_accounts' => []]);
        $this->guardrails = app(Guardrails::class);
    }

    /** A platform can have multiple distinct allowed ad accounts. */
    public function test_a_platform_can_have_multiple_allowed_accounts(): void
    {
        AllowedAdAccount::factory()->meta('act_1111111111')->create(['name' => 'Meta One']);
        AllowedAdAccount::factory()->meta('act_2222222222')->create(['name' => 'Meta Two']);

        AllowedAdAccount::factory()->google('3460855874')->create(['name' => 'Google Search']);
        AllowedAdAccount::factory()->google('9876543210')->create(['name' => 'Google Display']);

        $this->assertTrue($this->guardrails->allows('act_1111111111', 'meta'));
        $this->assertTrue($this->guardrails->allows('act_2222222222', 'meta'));
        $this->assertTrue($this->guardrails->allows('3460855874', 'google'));
        $this->assertTrue($this->guardrails->allows('9876543210', 'google'));

        $this->assertCount(2, $this->guardrails->permittedAccounts('meta'));
        $this->assertCount(2, $this->guardrails->permittedAccounts('google'));
    }

    /** One platform's database entry never authorizes another platform. */
    public function test_database_entries_are_isolated_by_platform(): void
    {
        AllowedAdAccount::factory()->meta('act_556447014')->create();
        AllowedAdAccount::factory()->google('3460855874')->create();
        AllowedAdAccount::factory()->linkedin('999888777')->create();

        // Meta entry does not authorize Google or LinkedIn
        $this->assertFalse($this->guardrails->allows('556447014', 'google'));
        $this->assertFalse($this->guardrails->allows('556447014', 'linkedin'));

        // Google customer ID does not authorize Meta
        $this->assertFalse($this->guardrails->allows('act_3460855874', 'meta'));
        $this->assertFalse($this->guardrails->allows('3460855874', 'meta'));

        // LinkedIn account does not authorize Meta
        $this->assertFalse($this->guardrails->allows('act_999888777', 'meta'));
    }

    /** Inactive accounts are refused by guardrails. */
    public function test_inactive_accounts_are_refused(): void
    {
        AllowedAdAccount::factory()->meta('act_1234567890')->inactive()->create();

        $this->assertFalse($this->guardrails->allows('act_1234567890', 'meta'));

        $this->expectException(MetaException::class);
        $this->guardrails->assertAccountAllowed('act_1234567890', 'meta');
    }

    /** Duplicate (platform, account_id) pairs are prevented by unique constraint. */
    public function test_duplicate_accounts_for_same_platform_are_prevented(): void
    {
        AllowedAdAccount::factory()->meta('act_1234567890')->create();

        $this->expectException(UniqueConstraintViolationException::class);
        AllowedAdAccount::factory()->meta('act_1234567890')->create();
    }

    /** The same account_id on different platforms is permitted. */
    public function test_same_id_on_different_platforms_is_allowed(): void
    {
        $meta = AllowedAdAccount::factory()->create(['platform' => 'meta', 'account_id' => 'act_556447014']);
        $linkedin = AllowedAdAccount::factory()->create(['platform' => 'linkedin', 'account_id' => '556447014']);

        $this->assertNotNull($meta->id);
        $this->assertNotNull($linkedin->id);
        $this->assertNotSame($meta->id, $linkedin->id);
    }

    /** The seeder parses env values and populates platform-specific database rows. */
    public function test_seeder_ingests_and_classifies_env_entries(): void
    {
        $raw = 'act_2220667645134722,act_1418821929380936,556447014,urn:li:sponsoredAccount:556447014,google:3460855874';

        $seeder = new AllowedAdAccountSeeder;
        $seeder->run($raw);

        // Meta accounts
        $this->assertTrue(AllowedAdAccount::isAllowed('act_2220667645134722', 'meta'));
        $this->assertTrue(AllowedAdAccount::isAllowed('act_1418821929380936', 'meta'));

        // LinkedIn account (bare ID and URN are normalized and deduplicated)
        $this->assertTrue(AllowedAdAccount::isAllowed('556447014', 'linkedin'));
        $this->assertSame(1, AllowedAdAccount::where('platform', 'linkedin')->count());

        // Google account with prefix
        $this->assertTrue(AllowedAdAccount::isAllowed('3460855874', 'google'));
    }

    /** If the database has no records, fallback to config is maintained. */
    public function test_guardrails_falls_back_to_config_when_database_is_empty(): void
    {
        $this->assertCount(0, AllowedAdAccount::all());

        config(['platforms.guardrails.allowed_ad_accounts' => ['act_fallback_123']]);

        $this->assertTrue($this->guardrails->allows('act_fallback_123', 'meta'));
        $this->assertFalse($this->guardrails->allows('act_unknown', 'meta'));
    }
}
