from django.http.response import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.template.loader import get_template
from django.template import RequestContext
from usercontrol.forms import RegistrationForm, LoginForm, ProfileForm, PasswordRecover, ChangePassword, ChangePasswordWQ
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login, logout
from usercontrol.models import UserProfile
from game.models import Devices
from django.core.mail import send_mail
from django.conf import settings
import hashlib
from django.db.models import Q
import random
from django.shortcuts import redirect
from PIL import Image
import datetime
import re
from datetime import timedelta
from django.utils import timezone
from django.utils.translation import ugettext as _
import requests


from django.contrib.auth.backends import ModelBackend

def parse_signed_request(signed_request, app_secret=settings.FACEBOOK_APP_SECRET):
    import hmac
    # import json
    from base64 import urlsafe_b64decode
    import simplejson as json
    app_secret = app_secret.encode('utf-8')
    try:
        l = signed_request.split('.', 2)
        encoded_sig = str(l[0])
        payload = str(l[1])
    except IndexError:
        raise ValueError("'signed_request' malformed")

    sig = urlsafe_b64decode(encoded_sig + "=" * ((4 - len(encoded_sig) % 4) % 4))
    data = urlsafe_b64decode(payload + "=" * ((4 - len(payload) % 4) % 4))

    data = json.loads(data)

    if data.get('algorithm').upper() != 'HMAC-SHA256':
        raise ValueError("'signed_request' is using an unknown algorithm")
    else:
        expected_sig = hmac.new(app_secret, msg=payload.encode('utf-8'), digestmod=hashlib.sha256).digest()

    if sig != expected_sig:
        raise ValueError("'signed_request' signature mismatch")
    else:
        return data



def send_new_password_recovery_key(username, first_time=False):
    # create recovery key
    salt = hashlib.sha1(str(random.random()).encode('utf-8')).hexdigest()[:5]
    password_recovery_key = hashlib.sha1(str(salt+username).encode('utf-8')).hexdigest()
    password_recovery_key_expires = datetime.datetime.today() + datetime.timedelta(2)


    user_pk = User.objects.get(username=username).pk
    profile = UserProfile.objects.filter(user=user_pk)
    profile.update(password_recovery_key=password_recovery_key, password_recovery_key_expires=password_recovery_key_expires)

    # send email with activation key
    email_subject = _('Восстановление пароля')
    template = get_template('usercontrol/email/password_recover.html')
    email_body = template.render({'email': username,
                                   'key': password_recovery_key,
                                   'first_time': first_time,
                                   'home_url': settings.DEFAULT_EMAIL_URL})
    try:
        send_mail(email_subject, email_body, settings.DEFAULT_FROM_EMAIL, ["%s" % username,], fail_silently=False)
    except:
        pass

def send_new_email_activation_key(username, first_time=False):
    # create activation key
    salt = hashlib.sha1(str(random.random()).encode('utf-8')).hexdigest()[:5]
    email_activation_key = hashlib.sha1(str(salt+username).encode('utf-8')).hexdigest()
    email_activation_key_expires = datetime.datetime.today() + datetime.timedelta(2)

    user_pk = User.objects.get(username=username).pk
    profile = UserProfile.objects.filter(user=user_pk)
    profile.update(email_activation_key=email_activation_key, email_activation_key_expires=email_activation_key_expires)

    # send email with activation key
    email_subject = _('Подтверждение регистрации')

    template = get_template('usercontrol/email/email_confirmation.html')
    # try:
    email_body = template.render({'email': username,
                                      'key': email_activation_key,
                                      'first_time': first_time,
                                      'home_url': settings.DEFAULT_EMAIL_URL})
    send_mail(email_subject, email_body, settings.DEFAULT_FROM_EMAIL, ["%s" % username,], fail_silently=False)
    # except:
    #     pass


def registration(request):
    if request.user.is_authenticated():
        return HttpResponseRedirect('/profile/')
    context = {'seo_title': _("Регистрация")}
    if request.method == 'POST' or request.method == 'GET' and 'code' in request.GET:
        form = RegistrationForm(request.POST)
        email_proof = False
        if form.is_valid() or form.cleaned_data['fbid'] or 'code' in request.GET:
            # VK AUTH BEGINS
            if 'code' in request.GET:
                vk_code = request.GET['code']
                data1 = requests.get('http://api.vk.com/oauth/access_token?'
                                     'client_id=5604935&'
                                     'client_secret=%s&'
                                     'code=%s&'
                                     'redirect_uri=http://ifolica.ru/signup/' % (settings.VK_APP_SECRET, vk_code))
                data1 = data1.json()
                if 'access_token' in data1:
                    username = data1['email']
                    data2 = requests.get('http://api.vk.com/method/users.get?'
                                         'uids=%s&'
                                         'fields=screen_name'
                                         'access_token=%s' % (data1['user_id'], data1['access_token']))
                    data2 = data2.json()
                    password = User.objects.make_random_password()
                    # name = "%s %s" % (data2['response'][0]['first_name'], data2['response'][0]['last_name'])
                    first_name = data2['response'][0]['first_name']
                    last_name = data2['response'][0]['last_name']
                    try:
                        user = User.objects.get(username=username)
                        user.backend = 'django.contrib.auth.backends.ModelBackend'
                        login(request, user)
                        return HttpResponseRedirect('/games/')
                    except:
                        email_proof = True
                else:
                    return HttpResponseRedirect('/signup/')
            # VK AUTH END

            if form.cleaned_data['fbid']:
                if not parse_signed_request(form.cleaned_data['signed_request']):
                    return HttpResponseRedirect('/login/')
                username = form.cleaned_data['fbusername']
                password = User.objects.make_random_password()
                first_name = form.cleaned_data['fbfirstname']
                last_name = form.cleaned_data['fblastname']
                try:
                    user = User.objects.get(username=username)
                    user.backend = 'django.contrib.auth.backends.ModelBackend'
                    login(request, user)
                    return HttpResponseRedirect('/games/')
                except:
                    email_proof = True
            elif not 'code' in request.GET:
                username = form.cleaned_data['username']
                password = form.cleaned_data['password']
                first_name = form.cleaned_data['first_name']
                last_name = form.cleaned_data['last_name']

            user = User.objects.create_user(username=username, email=username, password=password)
            user.save()
            user_profile = UserProfile(user=user,
                                       first_name=first_name,
                                       last_name=last_name,
                                       email_proof=email_proof)
            user_profile.save()

            if not email_proof:
                try:
                    send_new_email_activation_key(username)
                except:
                    pass

            try_auth = authenticate(username=username, password=password)
            if try_auth is not None:
                request.session.set_expiry(60*60*24*365)
                login(request, try_auth)
                return HttpResponseRedirect('/games/')
            else:
                return HttpResponseRedirect('/login/')

        else:
            context['form'] = form
            context['post'] = True
            return render(request, 'usercontrol/registration.html', context)
    else:
        context['form'] = RegistrationForm()
        return render(request, 'usercontrol/registration.html', context)


def login_request(request):
    if request.user.is_authenticated():
        return HttpResponseRedirect('/profile/')
    context = {'seo_title': _("Регистрация")}
    if request.method == 'POST' or 'code' in request.GET:
        form = LoginForm(request.POST)
        if form.is_valid() or not form.cleaned_data['fbusername'] == '' or 'code' in request.GET:
            # VK AUTH BEGINS
            if 'code' in request.GET:
                vk_code = request.GET['code']
                data1 = requests.get('https://api.vk.com/oauth/access_token?'
                                     'client_id=5604935&'
                                     'client_secret=%s&'
                                     'code=%s&'
                                     'redirect_uri=http://ifolica.ru/login/' % (settings.VK_APP_SECRET, vk_code))
                data1 = data1.json()
                try:
                    user = User.objects.get(username=data1['email'])
                    user.backend = 'django.contrib.auth.backends.ModelBackend'
                    login(request, user)
                    return HttpResponseRedirect('/games/')
                except User.DoesNotExist:
                    username = data1['email']
                    data2 = requests.get('http://api.vk.com/method/users.get?'
                                         'uids=%s&'
                                         'fields=screen_name'
                                         'access_token=%s' % (data1['user_id'], data1['access_token']))
                    data2 = data2.json()
                    password = User.objects.make_random_password()
                    # name = "%s %s" % (data2['response'][0]['first_name'], data2['response'][0]['last_name'])
                    first_name = data2['response'][0]['first_name']
                    last_name = data2['response'][0]['last_name']

                    user = User.objects.create_user(username=username, email=username, password=password)
                    user.save()
                    user_profile = UserProfile(user=user,
                                               first_name=first_name,
                                               last_name=last_name,
                                               email_proof=True,)
                    user_profile.save()
                    user.backend = 'django.contrib.auth.backends.ModelBackend'
                    login(request, user)
                    return HttpResponseRedirect('/games/')
                    # VK AUTH END

            if not form.cleaned_data['fbusername'] == '':
                if not parse_signed_request(form.cleaned_data['signed_request']):
                    return HttpResponseRedirect('/login/')
                try:
                    user = User.objects.get(username=form.cleaned_data['fbusername'])
                    user.backend = 'django.contrib.auth.backends.ModelBackend'
                    login(request, user)
                    return HttpResponseRedirect('/games/')
                except User.DoesNotExist:
                    first_name = form.cleaned_data['fbfirstname']
                    last_name = form.cleaned_data['fblastname']
                    username = form.cleaned_data['fbusername']
                    password = User.objects.make_random_password()
                    user = User.objects.create_user(username=username, email=username, password=password)
                    user.save()
                    user_profile = UserProfile(user=user,
                                               first_name=first_name,
                                               last_name=last_name,
                                               email_proof=True)
                    user_profile.save()
                    user.backend = 'django.contrib.auth.backends.ModelBackend'
                    login(request, user)
                    return HttpResponseRedirect('/games/')

            try_auth = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'])
            if try_auth is not None:
                if form.cleaned_data['remember_me']:
                    request.session.set_expiry(60*60*24*365)
                else:
                    request.session.set_expiry(0)
                login(request, try_auth)
                return HttpResponseRedirect('/games/')
            else:
                HttpResponseRedirect('/500/')
        else:
            return render(request, 'usercontrol/login.html', {'form': form, 'post': True})
    else:
        form = LoginForm()
        return render(request, 'usercontrol/login.html', {'form': form})


def password_recover(request):
    if request.method == 'POST':
        form = PasswordRecover(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            try:
                key_expires = User.objects.get(username=username).profile.password_recovery_key_expires
                password_recovery_key = User.objects.get(username=username).profile.password_recovery_key
                if not password_recovery_key or key_expires < timezone.now()+timedelta(hours=47):
                    send_new_password_recovery_key(username)

                    return render(request, 'usercontrol/login.html', {
                                              'sys_message': _('Инструкции по восстановлению пароля были отправлы на %s' % username)})
                else:
                    return render(request, 'usercontrol/password_recover.html', {'form': form, 'post': True,
                        'sys_error': True,
                        'sys_message': _('Восстановление пароля возможно не чаще чем 1 раз в час')})
            except User.DoesNotExist:
                return render(request, 'usercontrol/password_recover.html', {'form': form,
                                          'post': True,
                                          'sys_error': True,
                                          'sys_message': _('%s не зарегистрирован.' % username)})
        else:
            return render(request, 'usercontrol/password_recover.html', {'form': form, 'post': True})
    else:
        form = LoginForm()
        return render(request, 'usercontrol/password_recover.html', {'form': form})


def password_recover_link_activation(request, password_recovery_key):
    user_profile = get_object_or_404(UserProfile, password_recovery_key=password_recovery_key)

    if user_profile.password_recovery_key_expires and user_profile.password_recovery_key_expires < timezone.now():
        return render(request, 'usercontrol/login.html', {
            'sys_error': True,
            'seo_title': _("Log in"),
            'sys_message': _('Ссылка для восстановления пароля недействительна, <a href="/login/recover/">переотправить</a>')})

    context = {'username': user_profile.user.username}
    context['recovery_key'] = password_recovery_key
    context['sys_message'] = _('Смена пароля активирована')

    if request.method == 'POST':
        form = ChangePasswordWQ(request.POST)
        context['form'] = form
        if form.is_valid():
            new_password = form.cleaned_data['new_password']
            user_profile.user.set_password(new_password)
            user_profile.user.save()
            user_profile.password_recovery_key = ''
            user_profile.save()

            if not request.user.is_authenticated():
                try_auth = authenticate(username=user_profile.user.username, password=new_password)
                if try_auth is not None:
                    request.session.set_expiry(60*60*24*365)
                    login(request, try_auth)

            return render(request, 'usercontrol/profile.html', {
                'sys_message': "Пароль был изменен",
                'is_profile': True})
        else:
            context['sys_error'] = True
            context['sys_message'] = _('Error')

    return render(request, 'usercontrol/password_change.html', context)


def logout_request(request):
    if not request.user.is_authenticated():
        return redirect('/login/')
        # return render(request,  'usercontrol/login.html', context_instance=RequestContext(request))
    else:
        logout(request)
        return redirect('/login/')
        # return render(request,  'usercontrol/login.html',
        #                           {'sys_message': _('Logged out successfully'),
        #                            'seo_title': _("Your profile")},
        #                           context_instance=RequestContext(request))


def avatar_cropper(filename, crop=False, max_width=500):
    image = Image.open("%s/%s" % (settings.MEDIA_ROOT, filename))

    if image.mode not in ('L', 'RGB'):
        image = image.convert('RGB')
    width, height = image.size
    if width > max_width:
        for_percent = round((width-max_width)/(width/100))
        new_height = round(height/100*(100-for_percent))
        size = (max_width, new_height)
        image = image.resize(size, Image.ANTIALIAS)
    if crop:
        image = image.crop(crop)
    image.save("%s/%s" % (settings.MEDIA_ROOT, filename), image.format)
    return True


def profile_view(request):
    context = {'is_profile': True, 'seo_title': _("Ваш профиль")}
    return render(request, 'usercontrol/profile_view.html', context)


def profile_view_password_changed(request):
    context = {'is_profile': True,
               'sys_message': _('Пароль был изменен.'),
               'seo_title': _("Ваш профиль")}

    return render(request, 'usercontrol/profile_view.html', context)


def password_change_instantly(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/')
    context = {'is_password_change': True}
    if request.method == 'POST':
        form = ChangePassword(request.POST)
        if form.is_valid():
            # changing password
            new_password = form.clean_new_password()
            if new_password:
                request.user.set_password(new_password)
                request.user.save()
                # relogin after changing password
                try_auth = authenticate(username=request.user.username, password=new_password)
                if try_auth is not None:
                    request.session.set_expiry(60*60*24*365)
                    login(request, try_auth)
                else:
                    return HttpResponseRedirect('/login/')
                return HttpResponseRedirect('/profile/password_changed/')
        else:
            context = {'form': form,
                       'post': True,
                       'sys_message': _("Неправильный текущий пароль"),
                       'sys_error': True,
                       'is_password_change': True}
            return render(request, 'usercontrol/password_change_instantly.html', context)
    return render(request, 'usercontrol/password_change_instantly.html', context)


def profile(request):
    add_sys_message = ""
    context = {'seo_title': _("Учетные данные")}
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/')

    if request.method == 'POST':
        form = ProfileForm(request.POST, user=request.user)
        context['post'] = True

        context['form'] = form
        if form.is_valid():
            # changing password
            new_password = form.clean_new_password()
            if new_password:
                request.user.set_password(new_password)
                request.user.save()
                # relogin after changing password
                try_auth = authenticate(username=request.user.username, password=new_password)
                if try_auth is not None:
                    request.session.set_expiry(60*60*24*365)
                    login(request, try_auth)
                else:
                    return HttpResponseRedirect('/404/')

                add_sys_message = _(", пароль был изменен")

            # update profile
            user_profile_h = UserProfile.objects.get(user=request.user.id)
            user_profile_h.age = form.cleaned_data['age']
            user_profile_h.first_name = form.cleaned_data['first_name']
            user_profile_h.last_name = form.cleaned_data['last_name']
            user_profile_h.save()

            # update username
            username = form.clean_username()
            if username != request.user.username:
                if request.user.profile.email_last_changed and not request.user.profile.email_proof:
                    after_last_email_changed = timezone.now()-request.user.profile.email_last_changed
                    if after_last_email_changed < timedelta(hours=1):
                        to_wait = timedelta(hours=1) - after_last_email_changed
                        to_wait_minutes = round(to_wait.total_seconds()/60)
                        if request.user.profile.email_last_changed > timezone.now()-timedelta(days=1):

                            context['sys_error'] = True
                            context['sys_message'] = _('Смена пароля будет доступна через %s мин.'
                                                       % to_wait_minutes)
                            context['is_profile'] = True
                            context['is_profile_editing'] = True
                            return render(request, 'usercontrol/profile.html', context)
                request.user.username = username
                request.user.email = username
                request.user.profile.email_proof = False
                request.user.profile.email_last_changed = timezone.now()
                request.user.profile.save()
                request.user.save()

                send_new_email_activation_key(request.user.username)
                context['sys_message'] = _('Перейдите по ссылке, которую мы отправили на %s, чтобы подтвердить email' % request.user.username)
                context['is_profile'] = True
                context['is_profile_editing'] = True
                return render(request, 'usercontrol/profile.html', context)

            # form is valid
            context['sys_message'] = _('Профиль был сохранен %s') % add_sys_message
            context['is_profile'] = True
            return render(request, 'usercontrol/profile.html', context)
        # form is not valid
        else:
            context['sys_error'] = True
            context['sys_message'] = _('Профиль не был сохранен!')
            context['is_profile'] = True
            context['is_profile_editing'] = True
            return render(request, 'usercontrol/profile.html', context)
    # clean form
    form = ProfileForm(user=request.user)
    context['form'] = form
    context['is_profile'] = True
    context['is_profile_editing'] = True
    return render(request,  'usercontrol/profile.html', context)


def email_proof(request, email_activation_key):
    user_profile = get_object_or_404(UserProfile, email_activation_key=email_activation_key)

    if user_profile.email_proof:
        return render(request,  'usercontrol/profile.html', {
            'sys_message': _('%s подтвержден') % request.user.username,
            'is_profile': True})

    if user_profile.email_activation_key_expires < timezone.now():
        return render(request,  'usercontrol/profile.html', {
            'sys_error': True,
            'sys_message': _('Ссылка недействительна, <a href="/profile/activate/send/">переотправить ссылку</a>'),
            'is_profile': True})

    user_profile.email_proof = True
    user_profile.save()

    if not request.user.is_authenticated():
        # authenticate user if not after activation
        user = user_profile.user
        try_auth = authenticate(username=user.username, password=user.password)
        if try_auth is not None:
            request.session.set_expiry(60*60*24*365)
            login(request, try_auth)
        else:
            # couldn't authenticate after activation, is it possible?
            return HttpResponseRedirect('/404/')

    return render(request,  'usercontrol/profile.html', {
        'sys_message': _('%s подтвержден' % request.user.username),
        'is_profile': True})


def send_email_proof(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/')
    if request.user.profile.email_proof:
        return render(request,  'usercontrol/profile.html', {
            'sys_message': _('%s подтвержден, спасибо' % request.user.username),
            'is_profile': True})

    after_last_key_generated = timezone.now()-request.user.profile.email_activation_key_expires+timedelta(days=+2)
    # if after_last_key_generated < timedelta(hours=1):
    #     to_wait = timedelta(hours=1) - after_last_key_generated
    #
    #     # in minutes
    #     to_wait = round(to_wait.total_seconds()/60)
    #
    #     # if link requested more then one time a hour
    #     return render(request,  'usercontrol/profile.html', {
    #         'sys_error': True,
    #         'sys_message': _('Смена пароля может быть осуществлена не менее чем через %s мин.') % to_wait,
    #         'is_profile': True})
    try:
        send_new_email_activation_key(request.user.username)
    except:
        pass
    # after link sent
    return render(request,  'usercontrol/profile.html', {
        'sys_message': _('Чтобы подтвердить email перейдите по ссылке, что мы отправили на %s' % request.user.username),
        'is_profile': True})


def devices(request, remove_id = False):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/')
    context = {'is_objects': True, 'profile_h2': _("Devices"), 'seo_title': _("Devices")}
    if remove_id:
        try:
            Devices.objects.get(user=request.user, device_id=remove_id).delete()
            context['sys_message'] = "Устройство с ID '%s' успешно овязано." % remove_id
        except:
            pass
    context['devices'] = Devices.objects.filter(user=request.user)
    return render(request,  'usercontrol/devices.html', context)

