<?php

declare(strict_types=1);

namespace Apexl\Tests\User\UnitTests;

use apexl\Io\modules\user\enums\permissions\Common;
use apexl\Io\modules\user\interfaces\PermissionInterface;
use apexl\Io\modules\user\services\Permissions;
use apexl\Io\modules\user\services\RegisteredPermission;
use Apexl\Tests\User\Helpers\TestPermissionsEnum;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

/**
 * The permission registry's read contract. Pure — deliberately a plain TestCase
 * (no container, no DB).
 */
final class PermissionRegistryTest extends TestCase
{
    #[Test]
    public function map_is_empty_before_anything_is_registered(): void
    {
        self::assertSame([], new Permissions()->getPermissions());
    }

    #[Test]
    public function get_permission_returns_the_registered_enum_case(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'Manage users', 'Admin');

        $found = $registry->getPermission(TestPermissionsEnum::class . '::HAS_PERMISSION');

        self::assertInstanceOf(PermissionInterface::class, $found);
        self::assertSame(TestPermissionsEnum::HAS_PERMISSION, $found);
    }

    #[Test]
    public function get_permission_accepts_the_enum_case_itself(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(Common::VIEW, 'View');

        self::assertSame(Common::VIEW, $registry->getPermission(Common::VIEW));
    }

    #[Test]
    public function get_permission_is_null_for_an_unregistered_key(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'Manage users', 'Admin');

        self::assertNull($registry->getPermission('Nope\\Enum::MISSING'));
        self::assertNull($registry->getPermission(TestPermissionsEnum::DOES_NOT_HAVE_PERMISSION));
    }

    #[Test]
    public function registration_carries_the_friendly_name_and_group(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'Manage users', 'Admin');

        $entry = $registry->getRegistration(TestPermissionsEnum::HAS_PERMISSION);

        self::assertInstanceOf(RegisteredPermission::class, $entry);
        self::assertSame('Manage users', $entry->name);
        self::assertSame('Admin', $entry->group);
        self::assertSame(TestPermissionsEnum::HAS_PERMISSION, $entry->permission);
    }

    #[Test]
    public function group_defaults_to_general(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'Manage users');

        self::assertSame('General', $registry->getRegistration(TestPermissionsEnum::HAS_PERMISSION)?->group);
    }

    /** The shape existing consumers read off the map: ->name, ->group, keyed Enum::CASE. */
    #[Test]
    public function map_entries_keep_the_shape_consumers_read(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'Manage users', 'Admin');

        $map = $registry->getPermissions();
        $key = TestPermissionsEnum::class . '::HAS_PERMISSION';

        self::assertArrayHasKey($key, $map);
        self::assertSame('Manage users', $map[$key]->name);
        self::assertSame('Admin', $map[$key]->group);
    }

    /** json_encode output must match the stdClass the registry used to store. */
    #[Test]
    public function map_entries_json_encode_to_name_and_group_only(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'Manage users', 'Admin');

        $key = TestPermissionsEnum::class . '::HAS_PERMISSION';

        self::assertSame(
            '{"name":"Manage users","group":"Admin"}',
            json_encode($registry->getPermissions()[$key]),
        );
    }

    #[Test]
    public function re_registering_a_permission_replaces_its_labels(): void
    {
        $registry = new Permissions();
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'Old', 'Old group');
        $registry->registerPermission(TestPermissionsEnum::HAS_PERMISSION, 'New', 'New group');

        self::assertCount(1, $registry->getPermissions());
        self::assertSame('New', $registry->getRegistration(TestPermissionsEnum::HAS_PERMISSION)?->name);
    }
}
