import re
from datetime import datetime

from django.contrib.auth import authenticate
from django.contrib.auth import login as set_auth
from django.contrib.auth import logout as remove_auth
from django.contrib.auth.models import User
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponse, HttpResponseRedirect

from tauth.models import tUser
from tauth.settings import config

from .helper import render_template


def auth(request: WSGIRequest) -> HttpResponseRedirect:
    resp = HttpResponseRedirect("/")
    if "remove" in request.GET:
        resp.set_cookie("sessionid", "", max_age=0, expires=datetime(0, 0, 0))
    else:
        resp.set_cookie("sessionid", request.GET.get("sessionid") or "")

    return resp

def index(request: WSGIRequest) -> HttpResponse:
    if request.user.is_authenticated:
        return render_template(
            request, "index.html",
            username=request.user.get_username()
        )

    return render_template(
        request, "noauth/index.html",
        new_users=config["new_users"]
    )

def signup(request: WSGIRequest) -> HttpResponse:
    if request.user.is_authenticated:
        return HttpResponseRedirect("/")

    if config["new_users"]:
        if request.method == "POST":
            username = (request.POST.get("username") or "").lower().strip()
            password = (request.POST.get("password") or "")
            error = None

            if len(username) < 2 or len(username) > 30 or not re.match("^[a-z0-9_][a-z0-9_\\-]{0,28}[a-z0-9_]$", username):
                error = "Invalid username"

            elif len(password) < 6 or len(password) > 100 or not (any([i.isalpha() for i in password]) and any([i.isnumeric() for i in password]) and any([not i.isalnum() for i in password])):
                error = "Invalid password"

            elif username.lower() in password.lower():
                error = "Password can't contain username"

            else:
                try:
                    u = User.objects.create_user(
                        username=username,
                        password=password
                    )
                except User.DoesNotExist:
                    error = "Username already in use"
                else:
                    tUser.objects.create(user=u)
                    set_auth(request, u)
                    to = request.GET.get("to")

                    if to and to in config["services"] and config["services"][to]:
                        return HttpResponseRedirect(f"/redirect/?to={to}&reauth")

                    return HttpResponseRedirect("/")

            return render_template(
                request, "noauth/signup.html",
                title="Sign Up",
                error=error,
                login_extra=f"?to={request.GET.get('to')}" if "to" in request.GET else "",
                repopulate={
                    "username": username
                }
            )

        return render_template(
            request, "noauth/signup.html",
            title="Sign Up",
            login_extra=f"?to={request.GET.get('to')}" if "to" in request.GET else ""
        )

    return render_template(
        request, "404.html"
    )

def login(request: WSGIRequest) -> HttpResponse:
    if request.user.is_authenticated:
        to = request.GET.get("to")

        if to and to in config["services"] and config["services"]["to"]:
            return HttpResponseRedirect(f"/redirect/?to={to}&reauth")

        return HttpResponseRedirect("/")

    if request.method == "POST":
        username = (request.POST.get("username") or "").lower().strip()
        password = (request.POST.get("password") or "")

        user = authenticate(
            request,
            username=username,
            password=password
        )

        if user is None:
            return render_template(
                request, "noauth/login.html",
                title="Log In",
                new_users=config["new_users"],
                error="Username or password is incorrect",
                login_extra=f"?to={request.GET.get('to')}" if "to" in request.GET else "",
                repopulate={
                    "username": username
                }
            )

        set_auth(request, user)
        to = request.GET.get("to")

        if to and to in config["services"] and config["services"][to]:
            return HttpResponseRedirect(f"/redirect/?to={to}&reauth")

        return HttpResponseRedirect("/")


    return render_template(
        request, "noauth/login.html",
        title="Log In",
        new_users=config["new_users"],
        login_extra=f"?to={request.GET.get('to')}" if "to" in request.GET else ""
    )

def redirect(request: WSGIRequest) -> HttpResponseRedirect:
    to = request.GET.get("to")

    if to and to in config["services"] and config["services"][to]:
        return HttpResponseRedirect(config["services"][to]["url"]["pub"] + (f"/auth/?sessionid={request.COOKIES.get('sessionid')}" if "reauth" in request.GET else ""))

    return HttpResponseRedirect("/")

def logout(request: WSGIRequest) -> HttpResponseRedirect:
    remove_auth(request)
    to = request.GET.get("to")

    if to and to in config["services"] and config["services"][to]:
        return HttpResponseRedirect(config["services"][to]["url"]["pub"] + "/auth/?remove")

    return HttpResponseRedirect("/")
