<?php

declare(strict_types=1);

namespace App\Framework\Console\Security;

use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\FrameworkException;

final class SecurityException extends FrameworkException
{
    public function __construct(
        string $message,
        public readonly Permission|array $requiredPermissions,
        public readonly ConsoleUser $user,
        ?\Throwable $previous = null
    ) {
        parent::__construct($message, 403, $previous);
        $this->errorCode = ErrorCode::AUTH_INSUFFICIENT_PERMISSIONS;

        $this->withData([
            'user_id' => $user->id,
            'user_name' => $user->name,
            'user_permissions' => array_map(fn (Permission $p) => $p->value, $user->permissions),
            'required_permissions' => is_array($requiredPermissions)
                ? array_map(fn (Permission $p) => $p->value, $requiredPermissions)
                : [$requiredPermissions->value],
        ]);
    }

    public static function accessDenied(Permission $permission, ConsoleUser $user): self
    {
        return new self(
            "Access denied. Required permission: {$permission->value}",
            $permission,
            $user
        );
    }

    public static function insufficientPermissions(array $permissions, ConsoleUser $user, string $mode = 'any'): self
    {
        $permissionNames = array_map(fn (Permission $p) => $p->value, $permissions);

        return new self(
            "Access denied. Required {$mode} of permissions: " . implode(', ', $permissionNames),
            $permissions,
            $user
        );
    }
}
