import { JWTPayload } from '@/types';

/**
 * Browser-compatible JWT decoder
 * Only supports decoding (reading) JWT tokens, not signing/verifying
 */
export class JWTDecoder {
  /**
   * Decode a JWT token to extract the payload
   * @param token - The JWT token string
   * @returns The decoded payload or null if invalid
   */
  static decode(token: string): JWTPayload | null {
    try {
      if (!token || typeof token !== 'string') {
        return null;
      }

      // JWT tokens have 3 parts separated by dots: header.payload.signature
      const parts = token.split('.');
      if (parts.length !== 3) {
        return null;
      }

      // Get the payload (second part)
      const payload = parts[1];
      if (!payload) {
        return null;
      }
      
      // Decode base64url
      const decoded = this.base64UrlDecode(payload);
      
      // Parse JSON
      return JSON.parse(decoded) as JWTPayload;
    } catch (error) {
      console.error('JWT decode error:', error);
      return null;
    }
  }

  /**
   * Check if a JWT token is expired
   * @param token - The JWT token string
   * @returns true if expired, false if valid
   */
  static isExpired(token: string): boolean {
    try {
      const payload = this.decode(token);
      if (!payload || !payload.exp) {
        return true;
      }
      
      const currentTime = Date.now() / 1000;
      return payload.exp < currentTime;
    } catch {
      return true;
    }
  }

  /**
   * Get the expiration timestamp from a JWT token
   * @param token - The JWT token string
   * @returns The expiration timestamp or null if not found
   */
  static getExpiration(token: string): number | null {
    try {
      const payload = this.decode(token);
      return payload?.exp || null;
    } catch {
      return null;
    }
  }

  /**
   * Get time until token expiration in seconds
   * @param token - The JWT token string
   * @returns Seconds until expiration, 0 if expired or invalid
   */
  static getTimeUntilExpiration(token: string): number {
    try {
      const expirationTime = this.getExpiration(token);
      if (!expirationTime) return 0;
      
      const currentTime = Date.now() / 1000;
      const timeUntilExpiration = expirationTime - currentTime;
      return Math.max(0, timeUntilExpiration);
    } catch {
      return 0;
    }
  }

  /**
   * Decode base64url string to regular string
   * @param str - base64url encoded string
   * @returns decoded string
   */
  private static base64UrlDecode(str: string): string {
    // Convert base64url to base64
    let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
    
    // Add padding if needed
    while (base64.length % 4) {
      base64 += '=';
    }
    
    // Decode base64
    const decoded = atob(base64);
    
    // Convert to UTF-8
    return decodeURIComponent(
      decoded
        .split('')
        .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
        .join('')
    );
  }
}

// Export a default instance for convenience
export const jwtDecoder = JWTDecoder;