<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\Backend;

use stdClass;

/**
 * A resolved backend actor: the `tadminlogin` row the invoker acts as, plus the ready-made
 * `$_SESSION['AdminAccount']` payload that makes {@see \JTL\Backend\AdminAccount::validateSession()}
 * consider that actor logged in.
 *
 * Produced by {@see BackendIdentityFactory}; **installed** by
 * {@see GlobalStateSandbox} — this object never writes a superglobal itself.
 */
final readonly class AdminIdentity
{
    /**
     * @param int       $id      tadminlogin.kAdminlogin
     * @param string    $login   tadminlogin.cLogin — the value persisted as the OAuth token's cUserId
     * @param stdClass  $session the $_SESSION['AdminAccount'] payload, including ->oGroup
     */
    public function __construct(
        public int $id,
        public string $login,
        public stdClass $session,
    ) {
    }

    /**
     * The acting admin's permission group id. `=== \ADMINGROUP` means "every permission", which is
     * exactly what decision Q2 intends when that is the group the admin really has.
     */
    public function groupID(): int
    {
        return (int)($this->session->oGroup->kAdminlogingruppe ?? 0);
    }

    /**
     * The acting admin's real permission list (`tadminrechtegruppe.cRecht`). Empty for an
     * `\ADMINGROUP` member, whose access is short-circuited before the list is consulted
     * (`AdminAccount::permission()`, AdminAccount.php:375-377).
     *
     * @return list<string>
     */
    public function permissions(): array
    {
        $permissions = $this->session->oGroup->oPermission_arr ?? [];

        return \is_array($permissions) ? \array_values(\array_map('\strval', $permissions)) : [];
    }

    /**
     * Same verdict `AdminAccount::permission()` reaches (AdminAccount.php:375-377): membership of
     * `\ADMINGROUP` short-circuits to true, everyone else is checked against their real list.
     *
     * For a caller that already holds an {@see \JTL\Backend\AdminAccount} — the backend-action
     * invoker does — use that object instead; this exists for the paths that only ever build an
     * identity, such as {@see \Plugin\tnt_mcp\src\Mcp\Tools\SetSetting}.
     */
    public function has(string $permission): bool
    {
        return $this->groupID() === \ADMINGROUP || \in_array($permission, $this->permissions(), true);
    }
}
