<?php

namespace Tests\Feature;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\FeatureTestTrait;

/**
 * End-to-end per-endpoint scoping (qa-authorization-fixes).
 *
 * Drives the real DataTables JSON endpoints through routing + controllers to
 * prove the master-resolution fix at the endpoint level (not just the helper):
 *   - a linked sub-user (admin 17307 / viewer 17306 under master 17237) sees the
 *     MASTER account's rows (same recordsTotal as the master session), and
 *   - an unrelated account (15196) sees a DIFFERENT set (no cross-tenant leak).
 *
 * Assertions are data-independent (parity + inequality + non-empty), so they
 * survive drest refreshes. Runs against the dev Admin DB.
 */
final class MasterScopingTest extends CIUnitTestCase
{
    use FeatureTestTrait;

    private const MASTER     = 17237;
    private const ADMIN_SUB  = 17307;
    private const VIEWER_SUB = 17306;
    private const OTHER      = 15196;

    private int $obLevel = 0;

    protected function setUp(): void
    {
        parent::setUp();
        $this->obLevel = ob_get_level();
    }

    protected function tearDown(): void
    {
        while (ob_get_level() > $this->obLevel) {
            ob_end_clean();
        }
        parent::tearDown();
    }

    private function session(int $advId, string $role = 'admin'): array
    {
        return ['logged_in' => 1, 'adv_id' => $advId, 'user_id' => $advId, 'role' => $role];
    }

    private function recordsTotal(int $advId, string $uri, string $role = 'admin'): int
    {
        $res  = $this->withSession($this->session($advId, $role))->get($uri);
        $json = json_decode((string) $res->response()->getBody(), true);

        return is_array($json) && isset($json['recordsTotal']) ? (int) $json['recordsTotal'] : -1;
    }

    /* ── Campaigns (api/campaign/list) ─────────────────────────── */

    public function testCampaignSubUsersSeeMasterScope(): void
    {
        $master = $this->recordsTotal(self::MASTER, 'api/campaign/list');

        $this->assertGreaterThan(0, $master, 'master must have campaigns to make this test meaningful');
        $this->assertSame($master, $this->recordsTotal(self::ADMIN_SUB, 'api/campaign/list'), 'admin sub-user must see the master account campaigns');
        $this->assertSame($master, $this->recordsTotal(self::VIEWER_SUB, 'api/campaign/list', 'viewer'), 'viewer sub-user must see the master account campaigns');
    }

    public function testCampaignCrossAccountIsolated(): void
    {
        $master = $this->recordsTotal(self::MASTER, 'api/campaign/list');
        $other  = $this->recordsTotal(self::OTHER, 'api/campaign/list');

        $this->assertNotSame($master, $other, 'an unrelated account must not resolve to the master scope');
    }

    /* ── Creatives (api/creative/list) ─────────────────────────── */

    public function testCreativeSubUsersSeeMasterScope(): void
    {
        $master = $this->recordsTotal(self::MASTER, 'api/creative/list');

        $this->assertGreaterThan(0, $master, 'master must have creatives to make this test meaningful');
        $this->assertSame($master, $this->recordsTotal(self::ADMIN_SUB, 'api/creative/list'), 'admin sub-user must see the master account creatives');
        $this->assertSame($master, $this->recordsTotal(self::VIEWER_SUB, 'api/creative/list', 'viewer'), 'viewer sub-user must see the master account creatives');
    }

    public function testCreativeCrossAccountIsolated(): void
    {
        $master = $this->recordsTotal(self::MASTER, 'api/creative/list');
        $other  = $this->recordsTotal(self::OTHER, 'api/creative/list');

        $this->assertNotSame($master, $other, 'an unrelated account must not resolve to the master scope');
    }
}
