<?php

namespace MintyPHP\Service\Access;

class SettingsAuthorizationPolicy implements AuthorizationPolicyInterface
{
    public const ABILITY_ADMIN_SETTINGS_VIEW = 'admin.settings.view';
    public const ABILITY_ADMIN_SETTINGS_UPDATE = 'admin.settings.update';
    public const ABILITY_ADMIN_SETTINGS_BRANDING_UPDATE = 'admin.settings.branding.update';
    public const ABILITY_ADMIN_SETTINGS_TOKENS_REVOKE = 'admin.settings.tokens.revoke';
    public const ABILITY_ADMIN_SETTINGS_USER_LIFECYCLE_RUN = 'admin.settings.user_lifecycle.run';

    public function __construct(
        private readonly PermissionService $permissionService
    ) {
    }

    public function supports(string $ability): bool
    {
        return in_array($ability, [
            self::ABILITY_ADMIN_SETTINGS_VIEW,
            self::ABILITY_ADMIN_SETTINGS_UPDATE,
            self::ABILITY_ADMIN_SETTINGS_BRANDING_UPDATE,
            self::ABILITY_ADMIN_SETTINGS_TOKENS_REVOKE,
            self::ABILITY_ADMIN_SETTINGS_USER_LIFECYCLE_RUN,
        ], true);
    }

    public function authorize(string $ability, array $context = []): AuthorizationDecision
    {
        return match ($ability) {
            self::ABILITY_ADMIN_SETTINGS_VIEW => $this->authorizeAdminSettingsView($context),
            self::ABILITY_ADMIN_SETTINGS_UPDATE,
            self::ABILITY_ADMIN_SETTINGS_BRANDING_UPDATE,
            self::ABILITY_ADMIN_SETTINGS_TOKENS_REVOKE,
            self::ABILITY_ADMIN_SETTINGS_USER_LIFECYCLE_RUN => $this->authorizeSettingsUpdatePermission($context),
            default => AuthorizationDecision::deny(500, 'authorization_ability_not_supported'),
        };
    }

    private function authorizeAdminSettingsView(array $context): AuthorizationDecision
    {
        $actorUserId = $this->actorUserId($context);
        if (!$this->hasPermission($actorUserId, PermissionService::SETTINGS_VIEW)) {
            return AuthorizationDecision::deny(403, 'forbidden');
        }

        return AuthorizationDecision::allow([
            'capabilities' => [
                'can_view_page' => true,
                'can_update_settings' => $this->hasPermission($actorUserId, PermissionService::SETTINGS_UPDATE),
            ],
        ]);
    }

    private function authorizeSettingsUpdatePermission(array $context): AuthorizationDecision
    {
        $actorUserId = $this->actorUserId($context);
        if (!$this->hasPermission($actorUserId, PermissionService::SETTINGS_UPDATE)) {
            return AuthorizationDecision::deny(403, 'forbidden');
        }

        return AuthorizationDecision::allow();
    }

    private function actorUserId(array $context): int
    {
        return (int) ($context['actor_user_id'] ?? 0);
    }

    private function hasPermission(int $userId, string $permissionKey): bool
    {
        return $userId > 0 && $this->permissionService->userHas($userId, $permissionKey);
    }
}
