<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\OAuth\Repositories;

use JTL\DB\DbInterface;
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
use Plugin\tnt_mcp\src\Mcp\OAuth\Entities\AuthCodeEntity;
use stdClass;

/**
 * DB-backed authorization-code store (table tnt_mcp_oauth_auth_code). Codes are single-use and
 * short-lived; the row lets us reject a replayed or revoked code (deny-by-default).
 */
final class AuthCodeRepository implements AuthCodeRepositoryInterface
{
    public function __construct(private readonly DbInterface $db)
    {
    }

    public function getNewAuthCode(): AuthCodeEntityInterface
    {
        return new AuthCodeEntity();
    }

    public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity): void
    {
        $row            = new stdClass();
        $row->cCode     = $authCodeEntity->getIdentifier();
        $row->cClientId = $authCodeEntity->getClient()->getIdentifier();
        $row->cUserId   = (string)$authCodeEntity->getUserIdentifier();
        $row->cScopes   = ScopeJson::encode(\array_values($authCodeEntity->getScopes()));
        $row->dExpires  = $authCodeEntity->getExpiryDateTime()->format('Y-m-d H:i:s');
        $row->nRevoked  = 0;
        $row->dCreated  = (new \DateTimeImmutable())->format('Y-m-d H:i:s');

        $this->db->insert('tnt_mcp_oauth_auth_code', $row);
    }

    public function revokeAuthCode(string $codeId): void
    {
        $this->db->queryPrepared(
            'UPDATE tnt_mcp_oauth_auth_code SET nRevoked = 1 WHERE cCode = :id',
            ['id' => $codeId],
        );
    }

    public function isAuthCodeRevoked(string $codeId): bool
    {
        $row = $this->db->getSingleObject(
            'SELECT nRevoked FROM tnt_mcp_oauth_auth_code WHERE cCode = :id',
            ['id' => $codeId],
        );

        return $row === null || (int)$row->nRevoked === 1;
    }
}
