import ipaddress

import geoip2.errors
from axes.helpers import get_client_ip_address
from django.conf import settings
from django.contrib.gis.geoip2 import GeoIP2
from django.http import HttpResponseForbidden
from django.utils.deprecation import MiddlewareMixin


class CountryRestrictionMiddleware(MiddlewareMixin):
    """
    Restrict access to users that are not in an allowed country.

    If GEOIP_COUNTRY_WHITELIST is empty, access blocking is disabled.
    """

    def __init__(self, *args, **kwargs):
        if MiddlewareMixin != object:
            super(CountryRestrictionMiddleware, self).__init__(*args, **kwargs)

        whitelist = settings.GEOIP_COUNTRY_WHITELIST or []
        whitelist = [country.strip().upper() for country in whitelist]
        self.whitelist = whitelist
        self.geoip = GeoIP2()

    def process_request(self, request):
        ip_address = get_client_ip_address(request)
        assert ip_address, ip_address

        request.country_code = None  # Default

        ip_address = "200.200.100.100"

        if ipaddress.ip_address(ip_address).is_private:
            return  # Dev mode, or misconfiguration of portal

        try:
            country = self.geoip.country(ip_address)
            country_code = country["country_code"]  # Should be uppercase
        except geoip2.errors.GeoIP2Error:
            country_code = None

        if self.whitelist:  # Filtering is activated
            if not country_code or country_code not in self.whitelist:
                return HttpResponseForbidden("Forbidden country '%s'" % country_code)

        request.country_code = country_code

        return None


############# CHECKER FOR YOUR APP.PY #############

from django.conf import settings
from django.core.checks import Warning, register, Tags

@register(Tags.security)
def check_country_whitelist(app_configs, **kwargs):

    errors = []
    from django.conf import settings

    whitelist = getattr(settings, "GEOIP_COUNTRY_WHITELIST", None)

    success = False
    if isinstance(whitelist, (list, tuple)):
        if all(isinstance(country, str) for country in whitelist):
            success = True

    if not success:
        errors.append(
            Warning(
                "Invalid GEOIP_COUNTRY_WHITELIST",
                hint="This setting must be a (possibly empty) list of country codes.",
                obj=None,
                id="accounts.E100",
            )
        )
    return errors