from django.conf import settings
from django.contrib import auth, messages
from django.contrib.auth.decorators import login_required, user_passes_test
from django.db.models import Case, Value, When
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
from django.template.response import TemplateResponse
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
from django.views.generic import ListView
from django_tables2 import SingleTableMixin

from app.mixins import TabsViewMixin
from app.utils import reverse
from applications.models import Application, DraftApplication
from sponsors.models import Sponsor
from user import forms, models, tokens, providers
from user.forms import SetPasswordForm, PasswordResetForm
from user.mixins import IsOrganizerMixin
from user.models import User
from user.tokens import account_activation_token, password_reset_token
from .tables import OnDutyListTable


def login(request):
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('root'))
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        form = forms.LoginForm(request.POST)
        next_ = request.GET.get('next', '/')
        if form.is_valid():
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
            user = auth.authenticate(email=email, password=password)
            if user and user.is_active:
                auth.login(request, user)
                resp = HttpResponseRedirect(next_)
                c_domain = getattr(settings, 'LOGGED_IN_COOKIE_DOMAIN', getattr(settings, 'HACKATHON_DOMAIN', None))
                c_key = getattr(settings, 'LOGGED_IN_COOKIE_KEY', None)
                if c_domain and c_key:
                    try:
                        resp.set_cookie(c_key, 'biene', domain=c_domain, max_age=settings.SESSION_COOKIE_AGE)
                    except:
                        # We don't care if this is not set, we are being cool here!
                        pass
                return resp
            else:
                form.add_error(None, 'Incorrect username or password. Please try again.')

    else:
        form = forms.LoginForm()

    return render(request, 'login.html', {'form': form})


def signup(request):
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('root'))
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        form = forms.RegisterForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
            name = form.cleaned_data['name']

            if models.User.objects.filter(email=email).first() is not None:
                messages.error(request, 'An account with this email already exists')
            else:
                user = models.User.objects.create_user(email=email, password=password, name=name)
                user = auth.authenticate(email=email, password=password)
                auth.login(request, user)
                return HttpResponseRedirect(reverse('root'))
    else:
        form = forms.RegisterForm()

    return render(request, 'signup.html', {'form': form})


def logout(request):
    auth.logout(request)
    messages.success(request, 'Successfully logged out!')
    resp = HttpResponseRedirect(reverse('account_login'))
    c_domain = getattr(settings, 'LOGGED_IN_COOKIE_DOMAIN', None) or getattr(settings, 'HACKATHON_DOMAIN', None)
    c_key = getattr(settings, 'LOGGED_IN_COOKIE_KEY', None)
    if c_domain and c_key:
        try:
            resp.delete_cookie(c_key, domain=c_domain)
        except:
            # We don't care if this is not deleted, we are being cool here!
            pass
    return resp


def activate(request, uid, token, backend="django.contrib.auth.backends.ModelBackend"):
    try:
        uid = force_text(urlsafe_base64_decode(uid))
        user = User.objects.get(pk=uid)
        if request.user.is_authenticated and request.user != user:
            messages.warning(request, "Trying to verify wrong user. Log out please!")
            return redirect('root')
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        messages.warning(request, "This user no longer exists. Please sign up again!")
        return redirect('root')

    if account_activation_token.check_token(user, token):
        messages.success(request, "Email verified!")
        user.email_verified = True

        # CHECKING IF THE USER IS A SPONSOR
        user_email_domain = user.email.split('@')[1]  # Getting the domain of the user's email i.e @ugahacks.com
        if Sponsor.objects.filter(email_domain=user_email_domain):
            user.is_sponsor = True

        user.save()
        auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")
    else:
        messages.error(request, "Email verification url has expired. Log in so we can send it again!")
    return redirect('root')


def password_reset(request):
    if request.method == "POST":
        form = PasswordResetForm(request.POST, )
        if form.is_valid():
            email = form.cleaned_data.get('email')
            user = User.objects.get(email=email)
            msg = tokens.generate_pw_reset_email(user, request)
            msg.send()
            return HttpResponseRedirect(reverse('password_reset_done'))
        else:
            return TemplateResponse(request, 'password_reset_form.html', {'form': form})
    else:
        form = PasswordResetForm()
    context = {
        'form': form,
    }

    return TemplateResponse(request, 'password_reset_form.html', context)


def password_reset_confirm(request, uid, token):
    """
    View that checks the hash in a password reset link and presents a
    form for entering a new password.
    """
    try:
        uid = force_text(urlsafe_base64_decode(uid))
        user = User.objects.get(pk=uid)
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        return TemplateResponse(request, 'password_reset_confirm.html', {'validlink': False})

    if password_reset_token.check_token(user, token):
        if request.method == 'POST':
            form = SetPasswordForm(request.POST)
            if form.is_valid():
                form.save(user)
                return HttpResponseRedirect(reverse('password_reset_complete'))
        form = SetPasswordForm()
    else:
        return TemplateResponse(request, 'password_reset_confirm.html', {'validlink': False})

    return TemplateResponse(request, 'password_reset_confirm.html', {'validlink': True, 'form': form})


def password_reset_complete(request):
    return TemplateResponse(request, 'password_reset_complete.html', None)


def password_reset_done(request):
    return TemplateResponse(request, 'password_reset_done.html', None)


@login_required
def verify_email_required(request):
    if request.user.email_verified:
        messages.warning(request, "Your email has already been verified")
        return HttpResponseRedirect(reverse('root'))
    return TemplateResponse(request, 'verify_email_required.html', None)


@login_required
def set_password(request):
    if request.user.has_usable_password():
        return HttpResponseRedirect(reverse('root'))
    if request.method == 'GET':
        return TemplateResponse(request, 'callback.html', {'form': SetPasswordForm(), 'email': request.user.email})
    else:
        form = SetPasswordForm(request.POST)
        if form.is_valid():
            user = request.user
            form.save(user)
            auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")
            messages.success(request, 'Password correctly set')
            return HttpResponseRedirect(reverse('root'))
        return TemplateResponse(request, 'callback.html', {'form': form, 'email': request.user.email})


@login_required
def send_email_verification(request):
    if request.user.email_verified:
        messages.warning(request, "Your email has already been verified")
        return HttpResponseRedirect(reverse('root'))
    msg = tokens.generate_verify_email(request.user)
    msg.send()
    messages.success(request, "Verification email successfully sent")
    return HttpResponseRedirect(reverse('root'))


def callback(request, provider=None):
    if not provider:
        messages.error(request, 'Invalid URL')
        return HttpResponseRedirect(reverse('root'))
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('root'))
    code = request.GET.get('code', '')
    if not code:
        messages.error(request, 'Invalid URL')
        return HttpResponseRedirect(reverse('root'))
    try:
        access_token = providers.auth_mlh(code, request)
        mlhuser = providers.get_mlh_user(access_token)
    except ValueError as e:
        messages.error(request, str(e))
        return HttpResponseRedirect(reverse('root'))

    user = User.objects.filter(mlh_id=mlhuser.get('id', -1)).first()
    if user:
        auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")
    elif User.objects.filter(email=mlhuser.get('email', None)).first():
        messages.error(request, 'An account with this email already exists. Sign in using your password.')
    else:
        user = User.objects.create_mlhuser(
            email=mlhuser.get('email', None),
            name=mlhuser.get('first_name', '') + ' ' + mlhuser.get('last_name', None),
            mlh_id=mlhuser.get('id', None),
        )
        auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")

        # Save extra info
        draft = DraftApplication()
        draft.user = user
        mlhgender = mlhuser.get('gender','')
        if mlhgender == "I prefer not to say" or mlhgender not in dict(Application.GENDERS).values():
            mlhgender = "Prefer not to answer"
        mlhyear = mlhuser.get('level_of_study','')
        if mlhyear == "Not Currently a Student":
            mlhyear = Application.C_GRADUATED
        elif mlhyear == "University (Master's / Doctoral)":
            mlhyear = Application.C_GRAD
        else:
            mlhyear = Application.C_FRESHMAN
        draft.save_dict({
            'degree': mlhuser.get('major', ''),
            'university': mlhuser.get('school', {}).get('name', ''),
            'class_status': mlhyear,
            'phone_number': '(' + mlhuser.get('phone_number', '')[2:5] + ') ' + mlhuser.get('phone_number', '')[5:8] + '-' + mlhuser.get('phone_number', '')[8:],
            'gender': [k for k, v in Application.GENDERS if v == mlhgender][0],
        })
        draft.save()
    return HttpResponseRedirect(reverse('root'))


class OnDutyListView(TabsViewMixin, SingleTableMixin, ListView, IsOrganizerMixin):
    template_name = 'duty_list.html'
    table_class = OnDutyListTable
    table_pagination = {'per_page': 50}

    def get_queryset(self):
        return User.objects.all().filter(on_duty=True)

from django.conf import settings
from django.contrib import auth, messages
from django.contrib.auth.decorators import login_required, user_passes_test
from django.db.models import Case, Value, When
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
from django.template.response import TemplateResponse
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
from django.views.generic import ListView
from django_tables2 import SingleTableMixin

from app.mixins import TabsViewMixin
from app.utils import reverse
from applications.models import Application, DraftApplication
from sponsors.models import Sponsor
from user import forms, models, tokens, providers
from user.forms import SetPasswordForm, PasswordResetForm
from user.mixins import IsOrganizerMixin
from user.models import User
from user.tokens import account_activation_token, password_reset_token
from .tables import OnDutyListTable


def login(request):
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('root'))
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        form = forms.LoginForm(request.POST)
        next_ = request.GET.get('next', '/')
        if form.is_valid():
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
            user = auth.authenticate(email=email, password=password)
            if user and user.is_active:
                auth.login(request, user)
                resp = HttpResponseRedirect(next_)
                c_domain = getattr(settings, 'LOGGED_IN_COOKIE_DOMAIN', getattr(settings, 'HACKATHON_DOMAIN', None))
                c_key = getattr(settings, 'LOGGED_IN_COOKIE_KEY', None)
                if c_domain and c_key:
                    try:
                        resp.set_cookie(c_key, 'biene', domain=c_domain, max_age=settings.SESSION_COOKIE_AGE)
                    except:
                        # We don't care if this is not set, we are being cool here!
                        pass
                return resp
            else:
                form.add_error(None, 'Incorrect username or password. Please try again.')

    else:
        form = forms.LoginForm()

    return render(request, 'login.html', {'form': form})


def signup(request):
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('root'))
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        form = forms.RegisterForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
            name = form.cleaned_data['name']

            if models.User.objects.filter(email=email).first() is not None:
                messages.error(request, 'An account with this email already exists')
            else:
                user = models.User.objects.create_user(email=email, password=password, name=name)
                user = auth.authenticate(email=email, password=password)
                auth.login(request, user)
                return HttpResponseRedirect(reverse('root'))
    else:
        form = forms.RegisterForm()

    return render(request, 'signup.html', {'form': form})


def logout(request):
    auth.logout(request)
    messages.success(request, 'Successfully logged out!')
    resp = HttpResponseRedirect(reverse('account_login'))
    c_domain = getattr(settings, 'LOGGED_IN_COOKIE_DOMAIN', None) or getattr(settings, 'HACKATHON_DOMAIN', None)
    c_key = getattr(settings, 'LOGGED_IN_COOKIE_KEY', None)
    if c_domain and c_key:
        try:
            resp.delete_cookie(c_key, domain=c_domain)
        except:
            # We don't care if this is not deleted, we are being cool here!
            pass
    return resp


def activate(request, uid, token, backend="django.contrib.auth.backends.ModelBackend"):
    try:
        uid = force_text(urlsafe_base64_decode(uid))
        user = User.objects.get(pk=uid)
        if request.user.is_authenticated and request.user != user:
            messages.warning(request, "Trying to verify wrong user. Log out please!")
            return redirect('root')
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        messages.warning(request, "This user no longer exists. Please sign up again!")
        return redirect('root')

    if account_activation_token.check_token(user, token):
        messages.success(request, "Email verified!")
        user.email_verified = True

        # CHECKING IF THE USER IS A SPONSOR
        user_email_domain = user.email.split('@')[1]  # Getting the domain of the user's email i.e @ugahacks.com
        if Sponsor.objects.filter(email_domain=user_email_domain):
            user.is_sponsor = True

        user.save()
        auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")
    else:
        messages.error(request, "Email verification url has expired. Log in so we can send it again!")
    return redirect('root')


def password_reset(request):
    if request.method == "POST":
        form = PasswordResetForm(request.POST, )
        if form.is_valid():
            email = form.cleaned_data.get('email')
            user = User.objects.get(email=email)
            msg = tokens.generate_pw_reset_email(user, request)
            msg.send()
            return HttpResponseRedirect(reverse('password_reset_done'))
        else:
            return TemplateResponse(request, 'password_reset_form.html', {'form': form})
    else:
        form = PasswordResetForm()
    context = {
        'form': form,
    }

    return TemplateResponse(request, 'password_reset_form.html', context)


def password_reset_confirm(request, uid, token):
    """
    View that checks the hash in a password reset link and presents a
    form for entering a new password.
    """
    try:
        uid = force_text(urlsafe_base64_decode(uid))
        user = User.objects.get(pk=uid)
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        return TemplateResponse(request, 'password_reset_confirm.html', {'validlink': False})

    if password_reset_token.check_token(user, token):
        if request.method == 'POST':
            form = SetPasswordForm(request.POST)
            if form.is_valid():
                form.save(user)
                return HttpResponseRedirect(reverse('password_reset_complete'))
        form = SetPasswordForm()
    else:
        return TemplateResponse(request, 'password_reset_confirm.html', {'validlink': False})

    return TemplateResponse(request, 'password_reset_confirm.html', {'validlink': True, 'form': form})


def password_reset_complete(request):
    return TemplateResponse(request, 'password_reset_complete.html', None)


def password_reset_done(request):
    return TemplateResponse(request, 'password_reset_done.html', None)


@login_required
def verify_email_required(request):
    if request.user.email_verified:
        messages.warning(request, "Your email has already been verified")
        return HttpResponseRedirect(reverse('root'))
    return TemplateResponse(request, 'verify_email_required.html', None)


@login_required
def set_password(request):
    if request.user.has_usable_password():
        return HttpResponseRedirect(reverse('root'))
    if request.method == 'GET':
        return TemplateResponse(request, 'callback.html', {'form': SetPasswordForm(), 'email': request.user.email})
    else:
        form = SetPasswordForm(request.POST)
        if form.is_valid():
            user = request.user
            form.save(user)
            auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")
            messages.success(request, 'Password correctly set')
            return HttpResponseRedirect(reverse('root'))
        return TemplateResponse(request, 'callback.html', {'form': form, 'email': request.user.email})


@login_required
def send_email_verification(request):
    if request.user.email_verified:
        messages.warning(request, "Your email has already been verified")
        return HttpResponseRedirect(reverse('root'))
    msg = tokens.generate_verify_email(request.user)
    msg.send()
    messages.success(request, "Verification email successfully sent")
    return HttpResponseRedirect(reverse('root'))


def callback(request, provider=None):
    if not provider:
        messages.error(request, 'Invalid URL')
        return HttpResponseRedirect(reverse('root'))
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('root'))
    code = request.GET.get('code', '')
    if not code:
        messages.error(request, 'Invalid URL')
        return HttpResponseRedirect(reverse('root'))
    try:
        access_token = providers.auth_mlh(code, request)
        mlhuser = providers.get_mlh_user(access_token)
    except ValueError as e:
        messages.error(request, str(e))
        return HttpResponseRedirect(reverse('root'))

    user = User.objects.filter(mlh_id=mlhuser.get('id', -1)).first()
    if user:
        auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")
    elif User.objects.filter(email=mlhuser.get('email', None)).first():
        messages.error(request, 'An account with this email already exists. Sign in using your password.')
    else:
        user = User.objects.create_mlhuser(
            email=mlhuser.get('email', None),
            name=mlhuser.get('first_name', '') + ' ' + mlhuser.get('last_name', None),
            mlh_id=mlhuser.get('id', None),
        )
        auth.login(request, user, backend="django.contrib.auth.backends.ModelBackend")

        # Save extra info
        draft = DraftApplication()
        draft.user = user
        mlhgender = mlhuser.get('gender','')
        if mlhgender == "I prefer not to say" or mlhgender not in dict(Application.GENDERS).values():
            mlhgender = "Prefer not to answer"
        mlhyear = mlhuser.get('level_of_study','')
        if mlhyear == "Not Currently a Student":
            mlhyear = Application.C_GRADUATED
        elif mlhyear == "University (Master's / Doctoral)":
            mlhyear = Application.C_GRAD
        else:
            mlhyear = Application.C_FRESHMAN
        draft.save_dict({
            'degree': mlhuser.get('major', ''),
            'university': mlhuser.get('school', {}).get('name', ''),
            'class_status': mlhyear,
            'phone_number': '(' + mlhuser.get('phone_number', '')[2:5] + ') ' + mlhuser.get('phone_number', '')[5:8] + '-' + mlhuser.get('phone_number', '')[8:],
            'gender': [k for k, v in Application.GENDERS if v == mlhgender][0],
        })
        draft.save()
    return HttpResponseRedirect(reverse('root'))


class OnDutyListView(TabsViewMixin, SingleTableMixin, ListView, IsOrganizerMixin):
    template_name = 'duty_list.html'
    table_class = OnDutyListTable
    table_pagination = {'per_page': 50}

    def get_queryset(self):
        return User.objects.all().filter(on_duty=True)

# if this is a POST request we need to process the form data # We don't care if this is not set, we are being cool here! # if this is a POST request we need to process the form data # We don't care if this is not deleted, we are being cool here! # CHECKING IF THE USER IS A SPONSOR # Getting the domain of the user's email i.e @ugahacks.com View that checks the hash in a password reset link and presents a     form for entering a new password. # Save extra info