/**
 * JWT utilities for SentryAgent.ai AgentIdP.
 * Signs and verifies RS256 JWTs for agent access tokens.
 */

import jwt from 'jsonwebtoken';
import { ITokenPayload } from '../types/index.js';

const TOKEN_EXPIRES_IN = 3600; // 1 hour in seconds

/**
 * Signs a JWT access token using RS256 (RSA private key).
 *
 * @param payload - The token payload containing sub, client_id, scope, jti.
 * @param privateKey - PEM-encoded RSA private key.
 * @returns The signed JWT string.
 * @throws Error if signing fails.
 */
export function signToken(
  payload: Omit<ITokenPayload, 'iat' | 'exp'>,
  privateKey: string,
): string {
  const now = Math.floor(Date.now() / 1000);
  const fullPayload: ITokenPayload = {
    ...payload,
    iat: now,
    exp: now + TOKEN_EXPIRES_IN,
  };

  return jwt.sign(fullPayload, privateKey, { algorithm: 'RS256' });
}

/**
 * Verifies a JWT access token using RS256 (RSA public key).
 * Throws if the token is expired, has an invalid signature, or is malformed.
 *
 * @param token - The JWT string to verify.
 * @param publicKey - PEM-encoded RSA public key.
 * @returns The decoded, verified token payload.
 * @throws JsonWebTokenError | TokenExpiredError if verification fails.
 */
export function verifyToken(token: string, publicKey: string): ITokenPayload {
  const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
  return decoded as ITokenPayload;
}

/**
 * Decodes a JWT without verifying the signature.
 * Used for extracting claims (e.g. jti, exp) from tokens that may be expired.
 *
 * @param token - The JWT string to decode.
 * @returns The decoded payload or null if the token is malformed.
 */
export function decodeToken(token: string): ITokenPayload | null {
  const decoded = jwt.decode(token);
  if (!decoded || typeof decoded === 'string') {
    return null;
  }
  return decoded as ITokenPayload;
}

/**
 * Returns the token lifetime in seconds.
 *
 * @returns Token lifetime (3600 seconds = 1 hour).
 */
export function getTokenExpiresIn(): number {
  return TOKEN_EXPIRES_IN;
}
