/**
 * Auth Service
 * Handles JWT token generation and verification
 */

import jwt from 'jsonwebtoken';

export interface TokenPayload {
  user_id: string;
  [key: string]: any;
}

export class AuthService {
  private static get SECRET(): string {
    const secret = process.env.JWT_SECRET;
    if (!secret || secret === 'default-secret' || secret.length < 10) {
      throw new Error('JWT_SECRET environment variable is not set or is too weak');
    }
    return secret;
  }

  private static readonly EXPIRES_IN = '24h';

  /**
   * Generate a JWT token
   * @param payload - Token payload
   * @returns string - JWT token
   */
  static generateToken(payload: TokenPayload): string {
    // Get secret which will throw if invalid
    const secret = this.SECRET;

    return jwt.sign(payload, secret, {
      expiresIn: this.EXPIRES_IN,
    });
  }

  /**
   * Verify a JWT token
   * @param token - JWT token
   * @returns TokenPayload - Decoded token payload
   */
  static verifyToken(token: string): TokenPayload {
    try {
      const secret = this.SECRET;
      const decoded = jwt.verify(token, secret) as TokenPayload;
      return decoded;
    } catch (error) {
      if (error instanceof jwt.TokenExpiredError) {
        throw new Error('Token expired');
      }
      if (error instanceof jwt.JsonWebTokenError) {
        throw new Error('Invalid token');
      }
      throw error;
    }
  }

  /**
   * Extract token from Authorization header
   * @param authHeader - Authorization header value
   * @returns string | null - Extracted token or null
   */
  static extractTokenFromHeader(authHeader: string | undefined): string | null {
    if (!authHeader) {
      return null;
    }

    // Handle "Bearer <token>" format
    if (authHeader.startsWith('Bearer ')) {
      return authHeader.substring(7);
    }

    // Handle raw token
    return authHeader;
  }

  /**
   * Refresh an existing token
   * @param token - Existing token
   * @returns string - New token
   */
  static refreshToken(token: string): string {
    const decoded = this.verifyToken(token);
    // Add a small delay to ensure different iat
    // Generate new token with same payload
    const secret = this.SECRET;
    return jwt.sign({ user_id: decoded.user_id }, secret, {
      expiresIn: this.EXPIRES_IN,
    });
  }
}
