<?php

namespace Tests\Feature;

use App\Services\Dashboard\CampaignNameRepository;
use CodeIgniter\Test\CIUnitTestCase;

/**
 * The contract CampaignNameRepository owes its callers.
 *
 * The Dashboard renders $nameMap[$cid] straight into the table, so "every requested
 * id gets an entry" is load-bearing: the bug this class replaced was a name lookup
 * that silently returned nothing for a campaign and left the row showing
 * "Campaign 110855" while Campaign Performance showed the real name.
 *
 * These cases deliberately stay on the paths that reach no database - an empty id
 * list, ids that filter out, and advId 0 - so they assert the defaulting and
 * normalising logic without depending on what rows happen to exist in the Admin DB.
 */
final class CampaignNameRepositoryTest extends CIUnitTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        // Static memo, and the process is shared across cases.
        CampaignNameRepository::clearCache();
    }

    protected function tearDown(): void
    {
        CampaignNameRepository::clearCache();
        parent::tearDown();
    }

    public function testNoIdsAsksForNothing(): void
    {
        $repo = new CampaignNameRepository();

        $this->assertSame([], $repo->getNamesByCampaign(42, []));
    }

    public function testIdsThatCannotBeRealAreDroppedRatherThanDefaulted(): void
    {
        $repo = new CampaignNameRepository();

        // 0 and negatives are not campaigns; they must not come back as
        // "Campaign 0" rows in the table.
        $this->assertSame([], $repo->getNamesByCampaign(42, [0, -1, '0', 'abc']));
    }

    public function testEveryRequestedIdGetsAnEntryEvenWithNoAdvertiser(): void
    {
        $repo = new CampaignNameRepository();

        // advId 0 short-circuits the query, so this is purely the defaulting path.
        $out = $repo->getNamesByCampaign(0, [110855, 220]);

        $this->assertSame([
            110855 => 'Campaign 110855',
            220    => 'Campaign 220',
        ], $out);
    }

    public function testTheFallbackMatchesWhatCampaignPerformanceRenders(): void
    {
        $repo = new CampaignNameRepository();

        $out = $repo->getNamesByCampaign(0, [110855]);

        // Same string CampaignPerformanceFilterOptions::resolveCampaignNames() uses,
        // so an unresolvable campaign reads identically on both pages.
        $this->assertSame('Campaign 110855', $out[110855]);
    }

    public function testDuplicateAndStringIdsCollapseToOneIntKeyedEntry(): void
    {
        $repo = new CampaignNameRepository();

        $out = $repo->getNamesByCampaign(0, [110855, '110855', 110855]);

        $this->assertCount(1, $out);
        $this->assertArrayHasKey(110855, $out);
    }

    public function testKeysAreIntegersSoIntCastLookupsHit(): void
    {
        $repo = new CampaignNameRepository();

        // The presenter looks up $nameMap[(int) $cid]; string keys would miss.
        $out = $repo->getNamesByCampaign(0, ['110855']);

        foreach (array_keys($out) as $key) {
            $this->assertIsInt($key);
        }
    }
}
