# coding=utf-8
from __future__ import unicode_literals, absolute_import, print_function


import logging
import time
import hashlib
import datetime
from random import choice

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth import authenticate

from rpc.decorators import bind_context, bind

from rpc.context import Session

from rpc.tool.log_tool import auth_logger, logging_exception
from rpc.tool.error_code import gen, CODES
from rpc.tool.random_tool import random_str


from api.manager.user_manager import user_portraits, valid_nick_name
from api.models import POINTS_TYPE, LOGIN_AUTH_TYPE
from api.models import Person, UserExtra, UserExtraToCollege, UserExtraWechatInfo
from api.tool.auth_tool import get_auth_info
from api.tool.user_tool import get_user_extra_by_user_id, user_register_log_data
from api.tool.notification_tool import send_notification
from api.tool.verification_code import calc_verification_code
from api.tool.verification_code import anti_brute
from api.util.message_util import _send_welcome_notification
from api.util.wechat_util import get_wechat_access_token


def _login_dirty_work(ctx, user_id, lat, lng, device_info, new=False, cityname='', current_city_id=None):
    """what this func do.

        . add city for userextra
        . update device push info
        . follow_suozhang
        . send welcome notification
    """
    if not new:
        current_city_id = None

    from api.tasks.user_related_tasks import (
        set_city_by_lat_lng_or_cityname,
        follow_suozhang,
        update_device_pushinfo,
        record_device_info,
    )
    set_city_by_lat_lng_or_cityname.delay(user_id, lat, lng, cityname, current_city_id)

    if device_info:
        record_device_info(user_id=user_id, **device_info)
        update_device_pushinfo.delay(user_id=user_id, **device_info)

    if new:
        follow_suozhang.delay(user_id)
        _send_welcome_notification(user_id)


@bind_context("api/session/create")
def authorize(ctx, auth_type, auth_info, platform=None):
    """ 用于第三方登录
    :param ctx:
    :param auth_type: ["SinaWeibo", "QZone", "360"]
    :param auth_info
    :return:
    """
    access_token = auth_info['access_token']
    login_message = None

    dict = get_auth_info(auth_type, access_token)
    logging.info(dict)
    login_auth_type = dict["login_auth_type"]
    uid = dict["auth_user_id"]
    person = None

    if dict["error"] == 0:
        try:
            user = User.objects.get(username=uid)
            person = Person.get_or_create(user, platform=platform)
        except User.DoesNotExist:
            auth_logger.info('create new user')
            pwd = random_str(21)
            user = UserExtra.create_user(uid, "", pwd, login_auth_type)
            ctx.logger.app(**user_register_log_data(user_id=user.id))
            person = Person.get_or_create(user, platform=platform)
            login_message = u"注册成功"

        if user:
            user.backend = "django.contrib.auth.backends.ModelBackend"
            ctx.session.do_login(user)
            return {
                'success': True,
                'session': {
                    'key': ctx.session.session_key,
                },
                'user': {
                    'id': user.id,
                    'nickname': user.last_name,
                },
                'extra': {
                    'login_message': login_message,
                    'login_auth_type': login_auth_type,
                },
                'person': {
                    'phone': person.phone,
                }
            }
    else:
        login_message = dict["message"]

    return {
        'success': False,
        'session': None,
        'user': None,
        'extra': {
            'login_message': login_message,
        }
    }


@bind_context("api/login", show_document=False)
@bind_context("api/session/user_create")
def login(ctx, username, password, channel=None, lng=None, lat=None, device_info={}, platform=None):
    assert isinstance(username, basestring)
    assert isinstance(password, basestring)

    auth_logger.info("{0}, {1}, {2}, {3}, {4}, {5}".format(
        username, password, channel, lng, lat, device_info))

    # 用户名、密码登陆(已有用户)
    user = authenticate(username=username, password=password)
    login_message = None

    if anti_brute(username):
        return gen(CODES.USER_MAX_RETIES)

    user_extra = None
    new_register = False

    if user:
        auth_logger.info(u'password is ok')
        user_extra = get_user_extra_by_user_id(user.id)

    else:
        # 手机号码、验证码登录
        _pw = "%04d" % calc_verification_code(username)
        is_seccode_valid = str(_pw) == str(password)
        if not is_seccode_valid:
            # 验证码验证失败
            auth_logger.info(u'verification code is wrong')
            return gen(CODES.INVALID_CODE)

        # 手机验证码验证通过
        auth_logger.info(u'verification code is ok')

        try:
            user = User.objects.get(username=username)
            user_extra = get_user_extra_by_user_id(user.id, username)
            user_extra.phone = username
            user_extra.save()

            if not user.is_active:
                user = None

        except User.DoesNotExist:
            # 手机注册新用户
            auth_logger.info(u'register new user by phone number')

            new_register = True

            salt = time.time()
            m = hashlib.md5()
            m.update(str(salt))
            pwd = m.hexdigest()[:10]

            user = User.objects.create_user(username, "", pwd)
            ctx.logger.app(**user_register_log_data(user_id=user.id))
            if user:
                Person.get_or_create(user, platform=platform)

            user_extra = get_user_extra_by_user_id(user.id, username)
            if channel:
                user_extra.channel = channel
            user_extra.portrait = choice(user_portraits)
            user_extra.save()

            user.last_name = u'更美用户' + user_extra.referral_code
            user.save()
            login_message = u"注册成功"

    if user:
        Person.get_or_create(user, platform=platform)

    if user and user.is_active:
        user.backend = "django.contrib.auth.backends.ModelBackend"
        ctx.session.do_login(user)

        _login_dirty_work(ctx, user.id, lat, lng, device_info, new_register)

        if user_extra:
            user_extra.last_login = datetime.datetime.now()

        result = {
            u'success': True,
            u'session': {
                u'key': ctx.session.session_key,
            },
            u'user': {
                u'id': user.id,
                u'nickname': user.last_name,
            },
            u'extra': {
                u'login_message': login_message,
                u'new_register': new_register,
            }
        }
        return result

    return {
        u'success': False,
        u'session': None,
        u'user': None,
        u'extra': {
            u'login_message': login_message,
            u'new_register': new_register,
        }
    }


@bind_context("api/logout", login_required=True)
@bind_context("api/session/delete", login_required=True)
def logout(ctx):
    """
    退出登录
    """
    ctx.session.do_logout()
    return None


@bind_context('api/get_session_info')
@bind_context("api/session/get")
def get_session_info(ctx):
    return {
        'session': {
            'key': ctx.session.session_key,
        },
        'user': {
            'id': ctx.session.user.id,
            'is_authenticated': ctx.session.user.is_authenticated(),
        },
    }


@bind_context("api/session/wechat/get_info_by_appid")
def get_session_info(ctx, wechat_appid):
    openid = ctx.session.get_wechat_openid(wechat_appid)
    unionid = ctx.session.get_wechat_unionid()
    return {
        'openid': openid,
        'unionid': unionid,
    }


@bind_context("api/session/wechat/set_openid_by_appid")
def get_session_info(ctx, wechat_appid, openid, session_key=None):
    """
        这个接口可能会在刚刚登录完的时候被调用，此时client那边没有更新相关处理，没有传session_key
    """
    session = Session(session_key=session_key) if session_key else ctx.session
    session.set_wechat_openid(wechat_appid, openid)
    return {}


@bind_context("api/session/wechat/set_unionid")
def get_session_info(ctx, unionid, session_key=None):
    """
        这个接口可能会在刚刚登录完的时候被调用，此时client那边没有更新相关处理，没有传session_key
    """
    session = Session(session_key=session_key) if session_key else ctx.session
    session.set_wechat_unionid(unionid)
    return {}


@bind_context("api/session/3rdparty_user_create")
def thirdparty_user_create(ctx, auth_type, auth_user_id, auth_nickname,
                           portrait, city, channel, lng, lat, device_info={},
                           openid=None, platform=None, current_city_id=None, wechat_user_info=None):
    assert auth_type in (
        LOGIN_AUTH_TYPE.SinaWeibo, LOGIN_AUTH_TYPE.QZone,
        LOGIN_AUTH_TYPE.Wechat, LOGIN_AUTH_TYPE.WechatPub, LOGIN_AUTH_TYPE.WechatSmall,
        LOGIN_AUTH_TYPE.WechatSmall_MouthGun, LOGIN_AUTH_TYPE.MOMO,
    )

    login_message = None
    nickname_require_update = False
    new_register = False

    try:
        # NOTE: for old client, wechat login, auth_user_id is openid
        #       but we should use wechat's unionid as the username,
        #       update username as uniond id if user openid as username before
        user = User.objects.get(username=auth_user_id)
        if user:
            person = Person.get_or_create(user, platform=platform)

        user_extra = get_user_extra_by_user_id(user.id)

    except User.DoesNotExist:
        auth_logger.info('create new user')
        pwd = random_str(10)
        user = UserExtra.create_user(auth_user_id, "", pwd, auth_type)
        ctx.logger.app(**user_register_log_data(user_id=user.id))
        person = Person.get_or_create(user, platform=platform)

        new_register = True

        valid_info = valid_nick_name(auth_nickname)
        if valid_info['error'] == 0:
            user.last_name = auth_nickname.strip()
            user.save()

        login_message = u"注册成功"
        try:
            user_extra = get_user_extra_by_user_id(user.id)
            user_extra.channel = channel
            user_extra.auth_type = auth_type

            if portrait:
                user_extra.portrait = portrait
            else:
                user_extra.portrait = choice(user_portraits)

            user_extra.save()

        except Exception:
            logging_exception()

        if valid_info['error'] != 0:
            nickname_require_update = True

    if user:
        _login_dirty_work(
            ctx, user.id, lat, lng,
            device_info, new_register, city,
            current_city_id
        )

        user.backend = "django.contrib.auth.backends.ModelBackend"
        ctx.session.do_login(user)

        # 7750 保存微信授权登陆的用户信息
        if wechat_user_info:
            obj, created = UserExtraWechatInfo.objects.update_or_create(
                user_id=user.id,
                defaults= {
                    "openid": wechat_user_info['openId'],
                    "wechat_nickname": wechat_user_info['nickName']
                }
            )
            auth_logger.info('wechatusercreate %s' % obj.id)

        if user_extra:
            user_extra.last_login = datetime.datetime.now()
            college_info = UserExtraToCollege.objects.filter(userextra=user_extra).values(
                "college__id", "college__name").last()

        result = {
            u'session': {
                u'key': ctx.session.session_key,
            },
            u'user': {
                u'id': user.id,
                u'nickname': user.last_name,
            },
            u'extra': {
                u'login_message': login_message,
                u'new_register': new_register,
                u'nickname_require_update': nickname_require_update,
            },
            u'person': {
                u'id': person.id.hex,
                u'phone': person.phone
            },
            #  v 7.6.80 新增 返回用户的大学信息
            u"college": {
                u"id": college_info and college_info["college__id"] or 0,
                u"name": college_info and college_info["college__name"] or "",
            },
        }
        return result
    else:
        return gen(CODES.LOGIN_FAIL)

@bind('api/token/wechat_token')
def get_wechat_token():
    return get_wechat_access_token()