import jwt from 'jsonwebtoken';

export interface EmailVerificationTokenPayload {
  userId: string;
  email: string;
  purpose: 'email-verification';
  iat: number;
}

// In-memory token storage for validation (in production, consider Redis)
const activeTokens = new Map<string, EmailVerificationTokenPayload>();

/**
 * Generate a secure JWT token for email verification
 */
export async function generateEmailVerificationToken(userId: string, email: string): Promise<string> {
  const runtimeConfig = useRuntimeConfig();
  
  // Get JWT secret with multiple fallbacks
  const jwtSecret = (runtimeConfig.jwtSecret as string) || 
                   (runtimeConfig.sessionSecret as string) || 
                   (runtimeConfig.encryptionKey as string) || 
                   process.env.NUXT_JWT_SECRET ||
                   process.env.NUXT_SESSION_SECRET ||
                   process.env.NUXT_ENCRYPTION_KEY ||
                   'fallback-secret-key-for-email-tokens-please-configure-proper-jwt-secret';
  
  if (!jwtSecret || typeof jwtSecret !== 'string' || jwtSecret.length < 10) {
    throw new Error('JWT secret not configured properly. Please set NUXT_JWT_SECRET environment variable');
  }
  
  console.log('[email-tokens] Using JWT secret source:', 
    runtimeConfig.jwtSecret ? 'runtimeConfig.jwtSecret' :
    runtimeConfig.sessionSecret ? 'runtimeConfig.sessionSecret' :
    runtimeConfig.encryptionKey ? 'runtimeConfig.encryptionKey' :
    process.env.NUXT_JWT_SECRET ? 'NUXT_JWT_SECRET' :
    process.env.NUXT_SESSION_SECRET ? 'NUXT_SESSION_SECRET' :
    process.env.NUXT_ENCRYPTION_KEY ? 'NUXT_ENCRYPTION_KEY' : 'fallback');

  const payload: EmailVerificationTokenPayload = {
    userId,
    email: email.toLowerCase().trim(),
    purpose: 'email-verification',
    iat: Date.now()
  };

  const token = jwt.sign(payload, jwtSecret, { 
    expiresIn: '24h',
    issuer: 'monacousa-portal',
    audience: 'email-verification'
  });

  // Store token metadata for additional validation
  activeTokens.set(token, payload);
  
  // Clean up expired tokens periodically
  setTimeout(() => {
    activeTokens.delete(token);
  }, 24 * 60 * 60 * 1000); // 24 hours

  console.log('[email-tokens] Generated verification token for user:', userId, 'email:', email);
  
  return token;
}

/**
 * Verify and decode an email verification token
 */
export async function verifyEmailToken(token: string): Promise<{ userId: string; email: string }> {
  const runtimeConfig = useRuntimeConfig();
  
  // Get JWT secret with multiple fallbacks (same as generation)
  const jwtSecret = (runtimeConfig.jwtSecret as string) || 
                   (runtimeConfig.sessionSecret as string) || 
                   (runtimeConfig.encryptionKey as string) || 
                   process.env.NUXT_JWT_SECRET ||
                   process.env.NUXT_SESSION_SECRET ||
                   process.env.NUXT_ENCRYPTION_KEY ||
                   'fallback-secret-key-for-email-tokens-please-configure-proper-jwt-secret';
  
  if (!jwtSecret || typeof jwtSecret !== 'string' || jwtSecret.length < 10) {
    throw new Error('JWT secret not configured properly. Please set NUXT_JWT_SECRET environment variable');
  }

  if (!token) {
    throw new Error('Token is required');
  }

  try {
    // Verify JWT signature and expiration
    const decoded = jwt.verify(token, jwtSecret, {
      issuer: 'monacousa-portal',
      audience: 'email-verification'
    }) as any as EmailVerificationTokenPayload;

    // Validate token purpose
    if (decoded.purpose !== 'email-verification') {
      throw new Error('Invalid token purpose');
    }

    // Check if token exists in our active tokens (prevents replay attacks)
    const storedPayload = activeTokens.get(token);
    if (!storedPayload) {
      throw new Error('Token not found or already used');
    }

    // Validate payload consistency
    if (storedPayload.userId !== decoded.userId || storedPayload.email !== decoded.email) {
      throw new Error('Token payload mismatch');
    }

    // DON'T DELETE TOKEN YET - let the caller decide when to consume it
    console.log('[email-tokens] Successfully verified token for user:', decoded.userId, 'email:', decoded.email);

    return {
      userId: decoded.userId,
      email: decoded.email
    };

  } catch (error: any) {
    console.error('[email-tokens] Token verification failed:', error.message);
    
    // Provide user-friendly error messages
    if (error.name === 'TokenExpiredError') {
      throw new Error('Verification link has expired. Please request a new one.');
    } else if (error.name === 'JsonWebTokenError') {
      throw new Error('Invalid verification link.');
    } else {
      throw new Error(error.message || 'Token verification failed');
    }
  }
}

/**
 * Consume a token after successful operations
 */
export async function consumeEmailToken(token: string): Promise<void> {
  if (!token) {
    throw new Error('Token is required');
  }

  // Remove token from active tokens (single use)
  const wasRemoved = activeTokens.delete(token);
  
  if (wasRemoved) {
    console.log('[email-tokens] Token consumed successfully');
  } else {
    console.log('[email-tokens] Token was already consumed or not found');
  }
}

/**
 * Verify token without consuming it (for retries)
 */
export async function verifyEmailTokenWithoutConsuming(token: string): Promise<{ userId: string; email: string }> {
  // This is the same as verifyEmailToken but more explicit about not consuming
  return await verifyEmailToken(token);
}

/**
 * Check if a token is still valid without consuming it
 */
export async function isTokenValid(token: string): Promise<boolean> {
  try {
    const runtimeConfig = useRuntimeConfig();
    
    // Get JWT secret with multiple fallbacks (same as generation)
    const jwtSecret = (runtimeConfig.jwtSecret as string) || 
                     (runtimeConfig.sessionSecret as string) || 
                     (runtimeConfig.encryptionKey as string) || 
                     process.env.NUXT_JWT_SECRET ||
                     process.env.NUXT_SESSION_SECRET ||
                     process.env.NUXT_ENCRYPTION_KEY ||
                     'fallback-secret-key-for-email-tokens-please-configure-proper-jwt-secret';
    
    if (!jwtSecret || typeof jwtSecret !== 'string' || jwtSecret.length < 10 || !token) {
      return false;
    }

    const decoded = jwt.verify(token, jwtSecret, {
      issuer: 'monacousa-portal',
      audience: 'email-verification'
    }) as any as EmailVerificationTokenPayload;

    return decoded.purpose === 'email-verification' && activeTokens.has(token);
  } catch (error) {
    return false;
  }
}

/**
 * Clean up expired tokens from memory
 */
export function cleanupExpiredTokens(): void {
  const now = Date.now();
  const expirationTime = 24 * 60 * 60 * 1000; // 24 hours

  for (const [token, payload] of activeTokens.entries()) {
    if (now - payload.iat > expirationTime) {
      activeTokens.delete(token);
    }
  }

  console.log('[email-tokens] Cleaned up expired tokens. Active tokens:', activeTokens.size);
}

/**
 * Get statistics about active tokens
 */
export function getTokenStats(): { activeTokens: number; oldestToken: number | null } {
  const now = Date.now();
  let oldestToken: number | null = null;

  for (const payload of activeTokens.values()) {
    if (oldestToken === null || payload.iat < oldestToken) {
      oldestToken = payload.iat;
    }
  }

  return {
    activeTokens: activeTokens.size,
    oldestToken: oldestToken ? Math.floor((now - oldestToken) / 1000 / 60) : null // minutes ago
  };
}

// Periodic cleanup of expired tokens (every hour)
setInterval(cleanupExpiredTokens, 60 * 60 * 1000);
