/*
  Limite de tentativas por origem, na memoria do processo.

  Serve para o login e o cadastro do portal nao aceitarem mil senhas por
  minuto, e para a rota de pedido nao virar torneira. A loja roda num
  processo so em producao (pm2), entao a memoria basta; se um dia houver
  varios, o limite vale por processo, o que ainda e melhor que nenhum.

  Falhar aqui nunca derruba a rota: na duvida, deixa passar.
*/

type Janela = { contagem: number; abreEm: number };

const memoria = globalThis as unknown as { __limitesDeTentativas?: Map<string, Janela> };
const janelas = (memoria.__limitesDeTentativas ??= new Map<string, Janela>());
const TETO_DE_CHAVES = 10000;

export function origemDaRequisicao(request: Request) {
  const cabecalhos = request.headers;
  const encadeado = String(cabecalhos.get("x-forwarded-for") || "")
    .split(",")[0]
    .trim();
  return encadeado || String(cabecalhos.get("x-real-ip") || "").trim() || "sem-ip";
}

/**
 * Conta uma tentativa e diz se ela passa. `limite` tentativas a cada
 * `janelaSegundos` por chave (ip + rota + loja, por exemplo).
 */
export function tentativaPermitida(chave: string, limite: number, janelaSegundos: number): boolean {
  try {
    const agora = Date.now();
    const atual = janelas.get(chave);
    if (!atual || atual.abreEm + janelaSegundos * 1000 <= agora) {
      if (janelas.size >= TETO_DE_CHAVES) {
        const maisAntiga = janelas.keys().next().value;
        if (maisAntiga !== undefined) janelas.delete(maisAntiga);
      }
      janelas.set(chave, { contagem: 1, abreEm: agora });
      return true;
    }
    atual.contagem += 1;
    return atual.contagem <= limite;
  } catch {
    return true;
  }
}

/** Zera a contagem (por exemplo, depois de um login certo). */
export function esquecerTentativas(chave: string) {
  janelas.delete(chave);
}
