/**
 * Rate Limiter para Tentativas de Login
 * 
 * Limita tentativas de login para prevenir ataques de força bruta.
 * Armazena tentativas em sessionStorage (não persiste entre sessões).
 */

const MAX_ATTEMPTS = 5;
const WINDOW_MS = 15 * 60 * 1000; // 15 minutos
const BLOCK_DURATION_MS = 30 * 60 * 1000; // 30 minutos de bloqueio

/**
 * Chave para armazenar tentativas no sessionStorage
 * @param {string} identifier - Email ou identificador do usuário
 * @returns {string} Chave de armazenamento
 */
const getAttemptsKey = (identifier) => {
  return `login_attempts_${identifier.toLowerCase()}`;
};

/**
 * Chave para armazenar bloqueio
 * @param {string} identifier - Email ou identificador do usuário
 * @returns {string} Chave de bloqueio
 */
const getBlockKey = (identifier) => {
  return `login_blocked_${identifier.toLowerCase()}`;
};

/**
 * Registra uma tentativa de login
 * @param {string} identifier - Email ou identificador do usuário
 * @param {boolean} success - Se o login foi bem-sucedido
 * @returns {{allowed: boolean, attempts: number, blockedUntil: number|null}} Resultado
 */
export const recordLoginAttempt = (identifier, success) => {
  if (typeof window === 'undefined') {
    return { allowed: true, attempts: 0, blockedUntil: null };
  }
  
  if (!identifier) {
    return { allowed: true, attempts: 0, blockedUntil: null };
  }
  
  const attemptsKey = getAttemptsKey(identifier);
  const blockKey = getBlockKey(identifier);
  
  // Se login foi bem-sucedido, limpa tentativas
  if (success) {
    sessionStorage.removeItem(attemptsKey);
    sessionStorage.removeItem(blockKey);
    return { allowed: true, attempts: 0, blockedUntil: null };
  }
  
  // Verifica se está bloqueado
  const blockedUntil = sessionStorage.getItem(blockKey);
  if (blockedUntil) {
    const blockTime = parseInt(blockedUntil, 10);
    if (Date.now() < blockTime) {
      return {
        allowed: false,
        attempts: MAX_ATTEMPTS,
        blockedUntil: blockTime
      };
    } else {
      // Bloqueio expirou, remove
      sessionStorage.removeItem(blockKey);
      sessionStorage.removeItem(attemptsKey);
    }
  }
  
  // Obtém tentativas atuais
  const attemptsData = sessionStorage.getItem(attemptsKey);
  let attempts = [];
  
  if (attemptsData) {
    try {
      attempts = JSON.parse(attemptsData);
    } catch (e) {
      attempts = [];
    }
  }
  
  // Remove tentativas antigas (fora da janela de tempo)
  const now = Date.now();
  attempts = attempts.filter(timestamp => (now - timestamp) < WINDOW_MS);
  
  // Adiciona nova tentativa
  attempts.push(now);
  
  // Verifica se excedeu o limite
  if (attempts.length >= MAX_ATTEMPTS) {
    // Bloqueia por 30 minutos
    const blockUntil = now + BLOCK_DURATION_MS;
    sessionStorage.setItem(blockKey, blockUntil.toString());
    sessionStorage.setItem(attemptsKey, JSON.stringify(attempts));
    
    return {
      allowed: false,
      attempts: attempts.length,
      blockedUntil: blockUntil
    };
  }
  
  // Salva tentativas
  sessionStorage.setItem(attemptsKey, JSON.stringify(attempts));
  
  return {
    allowed: true,
    attempts: attempts.length,
    blockedUntil: null
  };
};

/**
 * Verifica se um identificador está bloqueado
 * @param {string} identifier - Email ou identificador do usuário
 * @returns {{blocked: boolean, blockedUntil: number|null}} Status de bloqueio
 */
export const isBlocked = (identifier) => {
  if (typeof window === 'undefined' || !identifier) {
    return { blocked: false, blockedUntil: null };
  }
  
  const blockKey = getBlockKey(identifier);
  const blockedUntil = sessionStorage.getItem(blockKey);
  
  if (!blockedUntil) {
    return { blocked: false, blockedUntil: null };
  }
  
  const blockTime = parseInt(blockedUntil, 10);
  const now = Date.now();
  
  if (now >= blockTime) {
    // Bloqueio expirou
    sessionStorage.removeItem(blockKey);
    sessionStorage.removeItem(getAttemptsKey(identifier));
    return { blocked: false, blockedUntil: null };
  }
  
  return {
    blocked: true,
    blockedUntil: blockTime
  };
};

/**
 * Obtém número de tentativas restantes
 * @param {string} identifier - Email ou identificador do usuário
 * @returns {number} Tentativas restantes
 */
export const getRemainingAttempts = (identifier) => {
  if (typeof window === 'undefined' || !identifier) {
    return MAX_ATTEMPTS;
  }
  
  const attemptsKey = getAttemptsKey(identifier);
  const attemptsData = sessionStorage.getItem(attemptsKey);
  
  if (!attemptsData) {
    return MAX_ATTEMPTS;
  }
  
  try {
    const attempts = JSON.parse(attemptsData);
    const now = Date.now();
    const validAttempts = attempts.filter(timestamp => (now - timestamp) < WINDOW_MS);
    return Math.max(0, MAX_ATTEMPTS - validAttempts.length);
  } catch (e) {
    return MAX_ATTEMPTS;
  }
};

/**
 * Limpa tentativas de um identificador
 * @param {string} identifier - Email ou identificador do usuário
 */
export const clearAttempts = (identifier) => {
  if (typeof window === 'undefined' || !identifier) {
    return;
  }
  
  sessionStorage.removeItem(getAttemptsKey(identifier));
  sessionStorage.removeItem(getBlockKey(identifier));
};

/**
 * Limpa todas as tentativas (útil para logout)
 */
export const clearAllAttempts = () => {
  if (typeof window === 'undefined') {
    return;
  }
  
  const keysToRemove = [];
  for (let i = 0; i < sessionStorage.length; i++) {
    const key = sessionStorage.key(i);
    if (key && (key.startsWith('login_attempts_') || key.startsWith('login_blocked_'))) {
      keysToRemove.push(key);
    }
  }
  
  keysToRemove.forEach(key => sessionStorage.removeItem(key));
};
