import random
import string
try:  # Python 2
    from urlparse import urljoin
except ImportError:  # Python 3
    from urllib.parse import urljoin

import requests
from flask import redirect, render_template, request, session, url_for, views
from flask_login import current_user, login_user, logout_user

from warmsea import app, db
from warmsea.admin import forms
from warmsea.models import User, UserBinding


@app.login_manager.user_loader
def load_user(user_id):
    return User.query.get(user_id)


class SignIn(views.MethodView):
    def get(self):
        if current_user.is_anonymous():
            return render_template('admin/signin.html',
                                   form=forms.SignInForm(),
                                   next_url=request.args.get('next', url_for('admin.index')))
        else:
            return redirect(request.args.get('next', url_for('admin.index')))

    def post(self):
        form = forms.SignInForm(request.form)
        if form.validate():
            user = User.verify(username=form.username.data, password=form.password.data)
            if user:
                login_user(user)
                return redirect(request.args.get('next', url_for('admin.index')))
            else:
                return render_template('admin/signin.html',
                                       form=forms.SignInForm(),
                                       errors=['Wrong username or password'])
        else:
            return render_template('admin/signin.html',
                                   form=forms.SignInForm(),
                                   errors=form.errors)  # TODO Or invalid username or password


def signout():
    redirect_uri = request.args.get('next', url_for('index'))
    logout_user()
    return redirect(redirect_uri)


def github_auth():
    if request.args['next']:
        session['github_auth_next_uri'] = request.args['next']
    github_grant_callback = requests.utils.quote(urljoin(app.config['URL_ROOT'], url_for('admin.github_auth_grant')))
    state = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(32))
    session['github_auth_state'] = state
    return redirect(''.join(['https://github.com/login/oauth/authorize',
                             '?client_id=' + app.config['GITHUB_APP_KEY'],
                             '&redirect_uri=' + github_grant_callback,
                             '&state=' + state]))


def github_auth_grant():
    state = request.args['state']
    if state != session['github_auth_state']:
        return signout()
    authorization_code = request.args['code']
    github_grant_callback = requests.utils.quote(urljoin(app.config['URL_ROOT'], url_for('admin.github_auth_grant')))
    redirect_uri = session.get('github_auth_next_uri', url_for('index'))
    access_token_uri = ''.join([
        'https://github.com/login/oauth/access_token',
        '?client_id=' + app.config['GITHUB_APP_KEY'],
        '&client_secret=' + app.config['GITHUB_APP_SECRET'],
        '&redirect_uri=' + github_grant_callback,
        '&code=' + authorization_code
    ])
    r = requests.post(access_token_uri, headers={'accept': 'application/json'}).json()
    access_token = r['access_token']
    whoami_uri = 'https://api.github.com/user?access_token=' + access_token
    r = requests.get(whoami_uri).json()
    binding_id = 'github:' + str(r['id'])
    binding = UserBinding.query.filter_by(binding=binding_id).first()
    if binding:
        user = User.query.get(binding.user_id)
    else:
        user = User(_username=binding_id,
                    _password='*',
                    nickname=r['login'],
                    avatar=r['avatar_url'],
                    website=r['blog'] or r['html_url'])
        db.session.add(user)
        db.session.commit()
        binding = UserBinding(binding=binding_id,
                              user_id=user.id)
        db.session.add(binding)
        db.session.commit()
    login_user(user)
    return redirect(redirect_uri)


def github_auth_revoke():
    signout()


def weibo_auth():
    if request.args['next']:
        session['weibo_auth_next_uri'] = request.args['next']
    weibo_grant_callback = requests.utils.quote(urljoin(app.config['URL_ROOT'], url_for('admin.weibo_auth_grant')))
    return redirect(''.join(['https://api.weibo.com/oauth2/authorize',
                             '?client_id=' + app.config['WEIBO_APP_KEY'],
                             '&response_type=code',
                             '&redirect_uri=' + weibo_grant_callback]))


def weibo_auth_grant():
    authorization_code = request.args['code']
    weibo_grant_callback = requests.utils.quote(urljoin(app.config['URL_ROOT'], url_for('admin.weibo_auth_grant')))
    redirect_uri = session.get('weibo_auth_next_uri', url_for('index'))
    access_token_uri = ''.join([
        'https://api.weibo.com/oauth2/access_token',
        '?client_id=' + app.config['WEIBO_APP_KEY'],
        '&client_secret=' + app.config['WEIBO_APP_SECRET'],
        '&grant_type=authorization_code',
        '&redirect_uri=' + weibo_grant_callback,
        '&code=' + authorization_code
    ])
    r = requests.post(access_token_uri).json()
    access_token, expires_in, uid = r['access_token'], r['expires_in'], r['uid']
    whoami_uri = ''.join(['https://api.weibo.com/2/users/show.json', '?access_token=' + access_token, '&uid=' + uid])
    r = requests.get(whoami_uri).json()
    binding_id = 'weibo:' + uid
    binding = UserBinding.query.filter_by(binding=binding_id).first()
    if binding:
        user = User.query.get(binding.user_id)
    else:
        user = User(_username=binding_id,
                    _password='*',
                    nickname=r['screen_name'],
                    avatar=r['profile_image_url'],
                    website=r['url'])
        db.session.add(user)
        db.session.commit()
        binding = UserBinding(binding=binding_id,
                              user_id=user.id)
        db.session.add(binding)
        db.session.commit()
    login_user(user)
    return redirect(redirect_uri)


def weibo_auth_revoke():
    signout()
