<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Security;

use App\Framework\Http\Session\SessionInterface;
use App\Framework\LiveComponents\Attributes\RequiresPermission;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;

/**
 * Session-based authorization checker for LiveComponent actions
 *
 * Checks user permissions stored in session against RequiresPermission attributes.
 *
 * Session Structure Expected:
 * ```php
 * $_SESSION['user'] = [
 *     'id' => 123,
 *     'permissions' => ['posts.view', 'posts.edit', 'comments.create'],
 *     'roles' => ['editor']
 * ];
 * ```
 *
 * Usage:
 * ```php
 * $checker = new SessionBasedAuthorizationChecker($session);
 *
 * if (!$checker->hasPermission('posts.delete')) {
 *     throw new UnauthorizedActionException('Missing posts.delete permission');
 * }
 * ```
 */
final readonly class SessionBasedAuthorizationChecker implements ActionAuthorizationChecker
{
    public function __construct(
        private SessionInterface $session
    ) {
    }

    /**
     * Check if action is authorized
     *
     * Authorization logic:
     * 1. No RequiresPermission attribute → always authorized
     * 2. User not authenticated → not authorized
     * 3. User has any of required permissions → authorized
     * 4. Otherwise → not authorized
     */
    public function isAuthorized(
        LiveComponentContract $component,
        string $method,
        ?RequiresPermission $permissionAttribute
    ): bool {
        // No permission requirement → allow access
        if ($permissionAttribute === null) {
            return true;
        }

        // User must be authenticated for permission-protected actions
        if (! $this->isAuthenticated()) {
            return false;
        }

        // Check if user has any of the required permissions
        $userPermissions = $this->getUserPermissions();

        return $permissionAttribute->isAuthorized($userPermissions);
    }

    /**
     * Get current user's permissions from session
     *
     * @return array<string>
     */
    public function getUserPermissions(): array
    {
        if (! $this->isAuthenticated()) {
            return [];
        }

        $user = $this->session->get('user');

        // Return permissions array or empty if not set
        return is_array($user) && isset($user['permissions'])
            ? (array) $user['permissions']
            : [];
    }

    /**
     * Check if user has specific permission
     */
    public function hasPermission(string $permission): bool
    {
        return in_array($permission, $this->getUserPermissions(), true);
    }

    /**
     * Check if user is authenticated
     *
     * User is considered authenticated if session contains 'user' data
     */
    public function isAuthenticated(): bool
    {
        return $this->session->has('user');
    }

    /**
     * Get user ID from session (for logging)
     */
    public function getUserId(): ?int
    {
        if (! $this->isAuthenticated()) {
            return null;
        }

        $user = $this->session->get('user');

        return is_array($user) && isset($user['id'])
            ? (int) $user['id']
            : null;
    }

    /**
     * Get user roles from session
     *
     * @return array<string>
     */
    public function getUserRoles(): array
    {
        if (! $this->isAuthenticated()) {
            return [];
        }

        $user = $this->session->get('user');

        return is_array($user) && isset($user['roles'])
            ? (array) $user['roles']
            : [];
    }
}
