from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect, render
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.conf import settings
from django.http import HttpResponse, HttpResponseBadRequest
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth import login as auth_login

from services.models import IPResource
from djadhere.utils import get_active_filter
from .forms import UserForm, ProfileForm

from ipaddress import ip_address, IPv6Address
from services.utils.ip_conversion import ipv6_to_ipv4


def login(request):
    def try_authenticate_from_ip():
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        try:
            ip = ip_address(ip)
        except ValueError:
            return
        try:
            if type(ip) == IPv6Address:
                ip = ipv6_to_ipv4(ip)
            ip = IPResource.objects.get(ip=ip.exploded)
        except (IPResource.DoesNotExist, ValueError):
            return
        allocation = ip.allocations.filter(get_active_filter()).first()
        if not allocation:
            return
        user = allocation.service.adhesion.user
        if not user: # corporation
            return
        if user.is_superuser: # superusers must enter password
            return
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
    if not request.session.get('disable-ip-based-login', False):
        try_authenticate_from_ip()
    # Même si l’auto-login a marché, on utilise LoginView qui fera la bonne redirection
    return LoginView.as_view(redirect_authenticated_user=True)(request)


def logout(request):
    response = LogoutView.as_view()(request)
    # Définie *après* car le logout flush la session
    request.session['disable-ip-based-login'] = True
    return response


@login_required
def profile(request):
    user_form = UserForm(request.POST or None, instance=request.user)
    profile_form = ProfileForm(request.POST or None, instance=request.user.profile)
    forms = [user_form, profile_form]
    if request.method == 'POST' and all(form.is_valid() for form in forms):
        for form in forms:
            form.save()
        messages.success(request, 'Profil mis à jour avec succès !')
        return redirect('profile')
    return render(request, 'accounts/profile.html', {
        'user_form': user_form,
        'profile_form': profile_form,
    })


@require_POST
@csrf_exempt
def auth_api(request, token):
    # token could not be None due to url regex
    if token != getattr(settings, 'AUTH_API_TOKEN', None):
        raise PermissionDenied
    username = request.POST.get('username')
    if not username:
        return HttpResponseBadRequest()
    password = request.POST.get('password')
    if password:
        user = authenticate(username=username, password=password)
        if user is None:
            return HttpResponse('<h1>401 Unauthorized</h1>', status=401)
    else:
        user = get_object_or_404(get_user_model(), username=username)
    required_groups = request.POST.get('groups')
    if required_groups and not user.is_superuser: # skip groups check for superusers
        required_groups = set(required_groups.split(' '))
        user_groups = set(map(lambda g: g.name, user.groups.all()))
        if required_groups - user_groups:
            return HttpResponse('<h1>401 Unauthorized</h1>', status=401)
    return HttpResponse()