/**
 * Component: JWT Token Utilities
 * Documentation: documentation/backend/services/auth.md
 */

import jwt from 'jsonwebtoken';
import { RMABLogger } from './logger';

const logger = RMABLogger.create('JWT');

const JWT_SECRET = process.env.JWT_SECRET || 'change-this-to-a-random-secret-key';
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || 'change-this-to-another-random-secret-key';
const JWT_DOWNLOAD_SECRET = process.env.JWT_DOWNLOAD_SECRET || JWT_SECRET + '-download';

const ACCESS_TOKEN_EXPIRY = '1h'; // 1 hour
const REFRESH_TOKEN_EXPIRY = '7d'; // 7 days

export interface TokenPayload {
  sub: string; // User ID
  plexId: string;
  username: string;
  role: string;
  iat?: number; // Issued-at (auto-set by jsonwebtoken)
}

export interface RefreshTokenPayload {
  sub: string;
  type: 'refresh';
  iat?: number; // Issued-at (auto-set by jsonwebtoken)
}

/**
 * Generate access token (short-lived)
 */
export function generateAccessToken(payload: TokenPayload): string {
  return jwt.sign(payload, JWT_SECRET, {
    expiresIn: ACCESS_TOKEN_EXPIRY,
  });
}

/**
 * Generate refresh token (long-lived)
 */
export function generateRefreshToken(userId: string): string {
  const payload: RefreshTokenPayload = {
    sub: userId,
    type: 'refresh',
  };

  return jwt.sign(payload, JWT_REFRESH_SECRET, {
    expiresIn: REFRESH_TOKEN_EXPIRY,
  });
}

/**
 * Verify access token
 */
export function verifyAccessToken(token: string): TokenPayload | null {
  try {
    const decoded = jwt.verify(token, JWT_SECRET) as TokenPayload;
    return decoded;
  } catch (error) {
    logger.error('Access token verification failed', { error: error instanceof Error ? error.message : String(error) });
    return null;
  }
}

/**
 * Verify refresh token
 */
export function verifyRefreshToken(token: string): RefreshTokenPayload | null {
  try {
    const decoded = jwt.verify(token, JWT_REFRESH_SECRET) as RefreshTokenPayload;
    if (decoded.type !== 'refresh') {
      return null;
    }
    return decoded;
  } catch (error) {
    logger.error('Refresh token verification failed', { error: error instanceof Error ? error.message : String(error) });
    return null;
  }
}

const DOWNLOAD_TOKEN_EXPIRY = '30d';

export interface DownloadTokenPayload {
  sub: string; // userId
  requestId: string;
  type: 'download';
}

/**
 * Generate download token (30-day, stateless, URL-embeddable)
 */
export function generateDownloadToken(userId: string, requestId: string): string {
  const payload: DownloadTokenPayload = { sub: userId, requestId, type: 'download' };
  return jwt.sign(payload, JWT_DOWNLOAD_SECRET, { expiresIn: DOWNLOAD_TOKEN_EXPIRY });
}

/**
 * Verify download token
 */
export function verifyDownloadToken(token: string): DownloadTokenPayload | null {
  try {
    const decoded = jwt.verify(token, JWT_DOWNLOAD_SECRET) as DownloadTokenPayload;
    if (decoded.type !== 'download') return null;
    return decoded;
  } catch {
    return null;
  }
}

/**
 * Decode token without verification (for debugging)
 */
export function decodeToken(token: string): any {
  try {
    return jwt.decode(token);
  } catch (error) {
    return null;
  }
}
