from django.shortcuts import redirect
from django.urls import reverse
from django.http import HttpResponse


class ActivationMiddleware:
    """
    Replaced by CompanyMiddleware which handles company resolution AND activation.
    This class is kept as a no-op stub so existing MIDDLEWARE config doesn't break.
    All activation checks are now done inside CompanyMiddleware.
    """
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        return self.get_response(request)


class LoginRateLimitMiddleware:
    """
    Blocks excessive login attempts from the same IP address.

    Rules:
      - 5 consecutive failures within LOGIN_FAIL_WINDOW seconds → block
      - Block duration: LOGIN_BLOCK_DURATION seconds
      - Uses Django's cache backend (works with locmem, redis, memcache, etc.)
      - Resets the failure count on a successful login (signal-based reset not needed
        because the counter key expires naturally after LOGIN_FAIL_WINDOW)

    Configuration (optional, in settings.py):
      LOGIN_FAIL_MAX      = 5       # failures before block (default 5)
      LOGIN_FAIL_WINDOW   = 600     # tracking window in seconds (default 10 min)
      LOGIN_BLOCK_DURATION = 900    # block duration in seconds (default 15 min)
    """

    LOGIN_URL_SUFFIX = '/accounts/login/'

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Only inspect POST to the login URL
        if request.method == 'POST' and request.path.endswith(self.LOGIN_URL_SUFFIX):
            ip = self._get_ip(request)
            if self._is_blocked(ip):
                return HttpResponse(
                    '<h2 style="font-family:sans-serif;text-align:center;margin-top:10vh;">'
                    '⛔ Too many failed login attempts.<br>'
                    '<small style="color:#64748b;">Please wait 15 minutes and try again.</small>'
                    '</h2>',
                    status=429,
                    content_type='text/html',
                )

        response = self.get_response(request)

        # After the view runs: if it's a successful login redirect (302 to non-login page)
        # reset the failure counter for this IP.
        if (
            request.method == 'POST'
            and request.path.endswith(self.LOGIN_URL_SUFFIX)
            and response.status_code in (301, 302)
        ):
            redirect_target = response.get('Location', '')
            if self.LOGIN_URL_SUFFIX not in redirect_target:
                # Successful login — clear failure count
                ip = self._get_ip(request)
                self._reset_failures(ip)

        return response

    # ── Helpers ──────────────────────────────────────────────────────────

    @staticmethod
    def _get_ip(request):
        """Return the best-guess client IP, respecting X-Forwarded-For."""
        xff = request.META.get('HTTP_X_FORWARDED_FOR')
        if xff:
            return xff.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR', '0.0.0.0')

    @staticmethod
    def _fail_key(ip):
        return f'login_fails_{ip}'

    @staticmethod
    def _block_key(ip):
        return f'login_blocked_{ip}'

    def _is_blocked(self, ip):
        from django.core.cache import cache
        from django.conf import settings
        max_fails     = getattr(settings, 'LOGIN_FAIL_MAX', 5)
        block_dur     = getattr(settings, 'LOGIN_BLOCK_DURATION', 900)

        # Already in explicit block?
        if cache.get(self._block_key(ip)):
            return True

        fails = cache.get(self._fail_key(ip), 0)
        if fails >= max_fails:
            # Transition to explicit block so the fail window can expire independently
            cache.set(self._block_key(ip), True, block_dur)
            return True
        return False

    def _reset_failures(self, ip):
        from django.core.cache import cache
        cache.delete(self._fail_key(ip))
        cache.delete(self._block_key(ip))


def _increment_login_failure(ip):
    """
    Called from accounts.views.login_view after a failed credential check.
    Increments the failure counter for the given IP in Django's cache.
    """
    from django.core.cache import cache
    from django.conf import settings
    window = getattr(settings, 'LOGIN_FAIL_WINDOW', 600)
    key = f'login_fails_{ip}'
    try:
        cache.incr(key)
    except ValueError:
        cache.set(key, 1, window)

