<?php

declare(strict_types=1);

namespace App\Framework\Auth\ValueObjects;

/**
 * Value Object for namespace-based access control
 *
 * Allows blocking entire controller namespaces (e.g., App\Application\Admin\*)
 * with optional allowlist for specific controllers.
 */
final readonly class NamespaceAccessPolicy
{
    /**
     * @param bool $isBlocked Whether this namespace is blocked
     * @param array<string> $allowedControllers Specific controller class names to allow despite block
     */
    public function __construct(
        private bool $isBlocked = false,
        private array $allowedControllers = []
    ) {
    }

    /**
     * Block all controllers in this namespace
     */
    public static function blocked(): self
    {
        return new self(isBlocked: true);
    }

    /**
     * Block namespace but allow specific controllers
     *
     * @param string ...$controllerClasses Full controller class names
     */
    public static function blockedExcept(string ...$controllerClasses): self
    {
        return new self(
            isBlocked: true,
            allowedControllers: $controllerClasses
        );
    }

    /**
     * Allow all controllers (no blocking)
     */
    public static function allowed(): self
    {
        return new self(isBlocked: false);
    }

    /**
     * Check if a specific controller is blocked
     *
     * @param string $controllerClass Full controller class name
     */
    public function isControllerBlocked(string $controllerClass): bool
    {
        if (! $this->isBlocked) {
            return false;
        }

        // Check if controller is in allowlist
        return ! in_array($controllerClass, $this->allowedControllers, true);
    }

    /**
     * Add controllers to allowlist
     */
    public function withAllowedControllers(string ...$controllerClasses): self
    {
        return new self(
            isBlocked: $this->isBlocked,
            allowedControllers: array_unique([...$this->allowedControllers, ...$controllerClasses])
        );
    }

    /**
     * Check if namespace has any restrictions
     */
    public function hasRestrictions(): bool
    {
        return $this->isBlocked;
    }
}
