<?php

namespace Tests\Feature;

use App\Models\AllowedAdAccount;
use App\Services\Platforms\Support\Guardrails;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

/**
 * "meta:*" opens Meta and says nothing about anyone else.
 *
 * On dev the allowed accounts change often enough that enumerating them is the
 * reason somebody eventually turns the guard off altogether, which is worse
 * than a wildcard because it is invisible. A prefixed star is the smallest
 * thing that removes the chore while still naming which platform it opens.
 *
 * A bare "*" is deliberately not honoured. entryFor() reads an unprefixed entry
 * as Google or LinkedIn and never Meta, so a lone star would open two platforms
 * and leave the third shut while reading like it opened everything.
 */
class APlatformWildcardOpensOnePlatformTest extends TestCase
{
    use RefreshDatabase;

    private function allowing(array $entries): Guardrails
    {
        config(['platforms.guardrails.allowed_ad_accounts' => $entries]);

        return app(Guardrails::class);
    }

    public function test_a_platform_wildcard_allows_any_account_on_that_platform(): void
    {
        $guard = $this->allowing(['meta:*']);

        $this->assertTrue($guard->allows('act_999999999999', 'meta'));
        $this->assertTrue($guard->allows('act_111111111111', 'meta'));
    }

    /** And leaves the other platforms exactly as shut as they were. */
    public function test_one_platforms_wildcard_does_not_open_another(): void
    {
        $guard = $this->allowing(['meta:*']);

        $this->assertFalse($guard->allows('3460855874', 'google'));
        $this->assertFalse($guard->allows('556447014', 'linkedin'));
    }

    /** Each platform can be opened on its own terms. */
    public function test_every_platform_can_carry_its_own_wildcard(): void
    {
        $guard = $this->allowing(['meta:*', 'google:*', 'linkedin:*']);

        $this->assertTrue($guard->allows('act_2220667645134722', 'meta'));
        $this->assertTrue($guard->allows('346-085-5874', 'google'));
        $this->assertTrue($guard->allows('urn:li:sponsoredAccount:556447014', 'linkedin'));
    }

    /**
     * A bare star opens nothing.
     *
     * Refused rather than guessed at, because the unprefixed rule would have
     * made it mean Google and LinkedIn but not Meta.
     */
    public function test_a_bare_star_is_not_a_wildcard(): void
    {
        $guard = $this->allowing(['*']);

        foreach (['meta' => 'act_1', 'google' => '123', 'linkedin' => '456'] as $platform => $id) {
            $this->assertFalse($guard->allows($id, $platform), "a bare star opened {$platform}");
        }
    }

    /**
     * The wildcard is not turned into an account id.
     *
     * Meta's branch adds the act_ prefix to anything without one, so an
     * unguarded wildcard became act_*, matched nothing, and made "meta:*" mean
     * the opposite of what it says.
     */
    public function test_the_wildcard_is_not_normalised_into_an_account(): void
    {
        $this->assertSame('*', AllowedAdAccount::normalizeAccountId('*', 'meta'));
        $this->assertSame('*', AllowedAdAccount::normalizeAccountId('*', 'google'));
        $this->assertSame('*', AllowedAdAccount::normalizeAccountId('*', 'linkedin'));
    }

    /** Named accounts still work alongside a wildcard for another platform. */
    public function test_named_accounts_still_work_beside_a_wildcard(): void
    {
        $guard = $this->allowing(['meta:*', '3460855874']);

        $this->assertTrue($guard->allows('act_777', 'meta'));
        $this->assertTrue($guard->allows('3460855874', 'google'));
        $this->assertFalse($guard->allows('9999999999', 'google'));
    }

    /** It works from the database too, which is where the list now lives. */
    public function test_a_wildcard_row_in_the_table_opens_the_platform(): void
    {
        config(['platforms.guardrails.allowed_ad_accounts' => []]);

        AllowedAdAccount::create([
            'platform' => 'linkedin',
            'account_id' => '*',
            'name' => 'All LinkedIn accounts (dev)',
            'is_active' => true,
        ]);

        $guard = app(Guardrails::class);

        $this->assertTrue($guard->allows('556447014', 'linkedin'));
        $this->assertFalse($guard->allows('act_1', 'meta'));
    }

    /** An inactive wildcard opens nothing, like any other inactive row. */
    public function test_an_inactive_wildcard_is_ignored(): void
    {
        config(['platforms.guardrails.allowed_ad_accounts' => []]);

        AllowedAdAccount::create([
            'platform' => 'linkedin',
            'account_id' => '*',
            'is_active' => false,
        ]);

        $this->assertFalse(app(Guardrails::class)->allows('556447014', 'linkedin'));
    }
}
