<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Attributes;

use Attribute;

/**
 * Marks a LiveComponent action as requiring specific permission
 *
 * Usage:
 * ```php
 * #[RequiresPermission('posts.delete')]
 * public function deletePost(string $postId): ComponentData
 * {
 *     // Only executed if user has 'posts.delete' permission
 * }
 * ```
 *
 * Multiple permissions (OR logic):
 * ```php
 * #[RequiresPermission('posts.edit', 'posts.admin')]
 * public function editPost(string $postId): ComponentData
 * {
 *     // User needs EITHER 'posts.edit' OR 'posts.admin'
 * }
 * ```
 *
 * Framework Integration:
 * - LiveComponentHandler checks this attribute before executing action
 * - Throws UnauthorizedActionException if permission check fails
 * - Integrates with AuthorizationChecker interface for flexible implementations
 */
#[Attribute(Attribute::TARGET_METHOD)]
final readonly class RequiresPermission
{
    /**
     * @var array<string> Required permissions (OR logic - user needs at least one)
     */
    public readonly array $permissions;

    /**
     * @param string ...$permissions Required permissions (OR logic - user needs at least one)
     */
    public function __construct(
        string ...$permissions
    ) {
        if (empty($permissions)) {
            throw new \InvalidArgumentException(
                'RequiresPermission attribute requires at least one permission'
            );
        }

        $this->permissions = $permissions;
    }

    /**
     * Check if user has any of the required permissions
     *
     * @param array<string> $userPermissions User's permissions
     */
    public function isAuthorized(array $userPermissions): bool
    {
        foreach ($this->permissions as $requiredPermission) {
            if (in_array($requiredPermission, $userPermissions, true)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Get all required permissions
     *
     * @return array<string>
     */
    public function getPermissions(): array
    {
        return $this->permissions;
    }

    /**
     * Get first permission (useful for error messages)
     */
    public function getPrimaryPermission(): string
    {
        return $this->permissions[0];
    }

    /**
     * Check if multiple permissions are required
     */
    public function hasMultiplePermissions(): bool
    {
        return count($this->permissions) > 1;
    }
}
