<?php

declare(strict_types=1);

namespace App\Domain\Audit;

/**
 * Per-request audit context — actor identity, source IP, and the
 * upstream-auth discriminator (`actorVia`).
 *
 * Resolved by AuditContextMiddleware from the active principal:
 * - service token + impersonation → actorKind=user, actorId=user_id
 *   (NOT the service token; per SPEC §8 the user is the responsible
 *   party). actorVia is `oidc` or `local` based on the user's `is_local`
 *   flag (SEC_REVIEW F11), so an auditor can filter rows by sign-in
 *   path without joining the users table.
 * - admin token → actorKind=admin-token, actorId=token_id, via=admin-token
 * - reporter / consumer tokens → actorKind=reporter / consumer, via mirrors
 * - service token without impersonation → actorKind=system, via=service
 *   (only the auth/upsert endpoints; bootstraps users without an actor)
 * - no principal at all (system-internal) → actorKind=system, via=system
 */
final class AuditContext
{
    public const KIND_USER = 'user';
    public const KIND_ADMIN_TOKEN = 'admin-token';
    public const KIND_REPORTER = 'reporter';
    public const KIND_CONSUMER = 'consumer';
    public const KIND_SYSTEM = 'system';

    public const VIA_OIDC = 'oidc';
    public const VIA_LOCAL = 'local';
    public const VIA_ADMIN_TOKEN = 'admin-token';
    public const VIA_SERVICE = 'service';
    public const VIA_REPORTER = 'reporter';
    public const VIA_CONSUMER = 'consumer';
    public const VIA_SYSTEM = 'system';

    public function __construct(
        public readonly string $actorKind,
        public readonly ?int $actorId,
        public readonly ?string $actorName,
        public readonly ?string $sourceIp,
        public readonly ?string $requestId,
        public readonly ?string $actorVia = null,
    ) {
    }

    public static function system(): self
    {
        return new self(self::KIND_SYSTEM, null, null, null, null, self::VIA_SYSTEM);
    }
}
