<?php

declare(strict_types=1);

namespace apexl\Io\modules\user\Actions;

use apexl\Config\Exceptions\MissingConfigException;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\modules\user\Factories\RefreshTokenFactory;
use apexl\Io\modules\user\interfaces\SessionManagerInterface;
use apexl\Io\modules\user\services\JwtCreator;
use Exception;
use Random\RandomException;

use function apexl\Io\config;

final readonly class StartLoggedInSession
{
    public function __construct(
        private JwtCreator $jwtCreator,
        private RefreshTokenFactory $refreshTokenCreator,
        private SessionManagerInterface $sessionManager,
    ) {}

    /**
     * @throws MissingConfigException
     * @throws RandomException
     * @throws Exception
     */
    public function handle(userEntity $user, bool $remember = false): array
    {
        $sessionId = $this->randomHexString();
        $token = $this->jwtCreator->forUser(
            $user,
            $sessionId,
        );

        $this->createSession($user->id, $sessionId);
        $this->updateUser($user);

        // "Stay signed in": store a longer per-row lifetime so this session
        // outlives a normal login. NULL keeps the config default.
        $lifetime = $remember ? (int) config('auth.refresh.lifetime_remember') : null;
        $refreshToken = $this->refreshTokenCreator->create($user->id, $lifetime);

        return [$token, $refreshToken];
    }

    /**
     * @throws RandomException
     */
    private function randomHexString(): string
    {
        return bin2hex(random_bytes(20));
    }

    private function createSession(int $userId, string $sessionId): void
    {
        $this->sessionManager->create($userId, $sessionId);
    }

    /**
     * @throws Exception
     */
    private function updateUser(userEntity $user): void
    {
        $user->last_login = time();
        $user->store();
    }
}