import logging
import time

from .exceptions import ThrottledException


class ThrottleMonitor:

  def __init__(self, config):
    self._n = config['n']
    self._period = config['period']
    self._reporter = config['reporter']
    self._state = {}
    self._blocked = set()

  async def block_ip(self, ip):
    if ip and (ip not in self._blocked):
      logging.critical('Blocking IP address due to call rate: %s' % ip)
      self._blocked.add(ip)
      await self._reporter.block_ip(ip)

  def check(self, ip):
    if ip in self._blocked:
      raise ThrottledException()

    # Keep the state clean
    now = time.time()
    old = []
    for ip, state in self._state.items():
      if now - state['t'] > self._period:
        old.append(ip)
      else:
        # Dictionaries preserve insertion order, so we know all the remaining records are within the period
        break
    for ip in old:
      del self._state[ip]

    if ip not in self._state:
      self._state[ip] = { 't': now, 'n': 0 }
    self._state[ip]['n'] += 1

    if self._state[ip]['n'] > self._n:
      raise ThrottledException()
