<?php

namespace App\Auth\Service;

use App\Auth\Entity\User;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Exception\AppException;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Contracts\Cache\CacheInterface;

class TokenService
{
    public function __construct(
        private readonly JWTTokenManagerInterface $jwtManager,
        private readonly CacheInterface           $cache,
        private readonly int                      $refreshTokenTtl = 2592000,
    ) {}

    public function issueTokens(User $user): array
    {
        $accessToken = $this->jwtManager->create($user);
        $rawToken    = $this->storeRefreshToken($user->getId());

        return [
            'access_token'             => $accessToken,
            'refresh_token'            => $rawToken,
            'token_type'               => 'Bearer',
            'expires_in'               => 900,
            'refresh_token_expires_in' => $this->refreshTokenTtl,
        ];
    }

    public function refreshToken(string $submittedToken): array
    {
        $key  = $this->refreshKey($submittedToken);
        $item = $this->cache->getItem($key);

        if (!$item->isHit()) {
            throw new AppException(ErrorCodes::ERR_AUTH_001, 'Refresh Token نامعتبر یا منقضی شده است', 401);
        }

        $userId = (int) $item->get();

        return ['userId' => $userId, 'rawToken' => $submittedToken];
    }

    public function revokeRefreshToken(string $rawToken): void
    {
        $this->cache->delete($this->refreshKey($rawToken));
    }

    private function storeRefreshToken(int $userId): string
    {
        $rawToken = bin2hex(random_bytes(32));
        $key      = $this->refreshKey($rawToken);

        $item = $this->cache->getItem($key);
        $item->set((string) $userId);
        $item->expiresAfter($this->refreshTokenTtl);
        $this->cache->save($item);

        return $rawToken;
    }

    private function refreshKey(string $rawToken): string
    {
        // hash → hex string → safe cache key (no reserved chars)
        return 'refresh_' . hash('sha256', $rawToken);
    }
}
