# -*- coding: UTF-8 -*-
from __future__ import absolute_import

import datetime
from gm_types.gaia import USER_CLASSIFY, USERCALL_EVENT_TYPE
from django.db.models import Q
from django.db import IntegrityError
from django.db import transaction
from django.utils.html import escape
from django.contrib.auth.models import User
from api.models.others import UserBlackList
from api.tool.user_tool import filter_user_nick_name, user_register_log_data, AddFansConfig
from api.models import VERIFY_CODE_TYPE, College
from api.tool.verification_code import VerifiedCode
from api.tool.image_utils import get_full_path
from rpc.decorators import bind_context, bind
from rpc.exceptions import (RPCIntegrityError, RPCNotFoundException, GaiaRPCFaultException)
from rpc.tool.log_tool import info_logger, logging_exception
from rpc.tool.log_tool import user_logger, logging_exception
from rpc.tool.dict_mixin import to_dict
from rpc.tool.random_tool import random_str
from ..datatables import UserDT
from hera.queries.user import UserDQ
from hera.utils import reset_username
from hera.models import BackendGroup
from api.models.types import LOGIN_AUTH_TYPE
from api.models.user import UserExtra, UserExtraToCollege, UserInnerInfo
from api.models.phone_protect import ProtectPhone
from api.models.person import Person
from hera.utils import send_user_passwd_email_v2
from hera.queries.choice_query import choice_query
from api.tool.person import update_password
from api.tool.user_tool import get_user_from_context
from django.conf import settings
from social.models import UserFollow

from talos.models.live import LiveWhiteList, ShortvideoBlackList
from services.talos_service import (
    diary_count, topic_reply_filter, topic_count,
)
from statistic.models import ClassifyUser

uri_pre = 'hera/user'


@bind_context(uri_pre + '/choices')
def user_choices(ctx, q='', page=1, num=30, initial=None, group=None, is_staff=None, livewhitelist=False,
                 withoutlivewhitelist=False, withoutshortvideoblacklist=False, can_send_msg=False, puppet_user=None):
    page = int(page)
    num = int(num)

    query = choice_query(User, ['id', 'username', 'last_name'], 'id', q, initial)
    if group is not None:
        query = query.filter(belong_groups__name=group)
    if is_staff is not None:
        query = query.filter(is_staff=is_staff)
    if livewhitelist:
        user_ids = LiveWhiteList.objects.values_list('user_id', flat=True)
        query = query.filter(id__in=list(user_ids))
    if withoutlivewhitelist:
        user_ids = LiveWhiteList.objects.values_list('user_id', flat=True)
        query = query.exclude(id__in=list(user_ids))
    if withoutshortvideoblacklist:
        user_ids = ShortvideoBlackList.objects.values_list('user_id', flat=True)
        query = query.exclude(id__in=list(user_ids))
    if can_send_msg:
        query = query.filter(id__in=settings.DOCTOR_USER_CAN_SEND_MSG)
    if puppet_user:
        query = query.filter(person__is_puppet=True)
    # total_count = query.count()
    total_count = 0
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0
    results = [{
                   'id': u.id,
                   'text': u'{}:{}'.format(u.id,
                                           u.username if not u.last_name or '***' in u.last_name else u.last_name),
               } for u in query[start_pos: start_pos + num]]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}


# 仅仅是想用person_id, 从上面完整复制下来的
@bind_context(uri_pre + '/person/choices')
def user_person_choices(
        ctx, q='', page=1, num=30, initial=None, group=None, is_staff=None, livewhitelist=False,
        withoutlivewhitelist=False, withoutshortvideoblacklist=False, can_send_msg=False, puppet_user=None):
    page = int(page)
    num = int(num)

    query = choice_query(User, ['id', 'username', 'last_name'], 'id', q, initial)
    if group is not None:
        query = query.filter(belong_groups__name=group)
    if is_staff is not None:
        query = query.filter(is_staff=is_staff)
    if livewhitelist:
        user_ids = LiveWhiteList.objects.values_list('user_id', flat=True)
        query = query.filter(id__in=user_ids)
    if withoutlivewhitelist:
        user_ids = LiveWhiteList.objects.values_list('user_id', flat=True)
        query = query.exclude(is__in=user_ids)
    if withoutshortvideoblacklist:
        user_ids = ShortvideoBlackList.objects.values_list('user_id', flat=True)
        query = query.filter(id__in=user_ids)
    if can_send_msg:
        query = query.filter(id__in=settings.DOCTOR_USER_CAN_SEND_MSG)
    if puppet_user:
        query = query.filter(person__is_puppet=True)
    # total_count = query.count()
    total_count = 0
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0
    results = [{
                   'id': u.person.id.hex,
                   'text': u'{}:{}'.format(u.id,
                                           u.username if not u.last_name or '***' in u.last_name else u.last_name),
               } for u in query[start_pos: start_pos + num]]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}


@bind_context(uri_pre + '/choices/random')
def user_random_choices(ctx, group=None):
    query = User.objects.all()
    if group is not None:
        query = query.filter(belong_groups__name=group)
    user = query.order_by('?').first()
    name = filter_user_nick_name(user)
    return {'id': user.id, 'text': u'{}:{}'.format(user.id, name)}


@bind_context(uri_pre + '/list')
def user_datatable(ctx, req_data):
    dtobj = UserDT(User)
    return dtobj.process(req_data)


@bind_context(uri_pre + '/query')
def user_query(ctx, options):

    user_logger.info("查询用户信息---")
    dqobj = UserDQ()

    return dqobj.process(**options)


@bind_context(uri_pre + '/get')
def user_get(ctx, user_id, options=None):
    try:
        user = User.objects.get(id=user_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    user_data = to_dict(user, **options)
    return user_data


@bind_context(uri_pre + '/edit')
def user_edit(ctx, user_id=None, user_info=None):
    if user_info is None:
        return None
    interest_college = user_info.pop('interest_college', '')
    if user_info['blacklist']:
        user_black, _ = UserBlackList.objects.get_or_create(bind_user_id=user_id)
        for device in user_black.bind_user.devices.all():
            UserBlackList.objects.get_or_create(device_id=device.id)
    else:
        UserBlackList.delete_by_user_id(user_id)

    if user_id is None:
        try:
            user = User.objects.create(**user_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:  # UserExtra保存头像和达人
        try:
            extra = UserExtra.objects.get(user_id=user_id)
            if interest_college:
                obj = College.objects.get(id=interest_college)
                UserExtraToCollege.objects.get_or_create(college_id=obj.id, userextra_id=extra.id)
            else:
                UserExtraToCollege.objects.filter(userextra_id=extra.id).delete()
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
        for k, v in user_info.iteritems():
            setattr(extra, k, v)
        extra.save()
    return user_id


@bind_context(uri_pre + '/detail')
def user_detail(ctx, user_id):
    obj = User.objects.get(id=user_id)
    interest_college = UserExtraToCollege.objects.filter(userextra__user_id=user_id).last()
    device_list = []
    for i in obj.devices.all():
        device_list.append(str(i.id))

    auth_type = ''
    membership_level = False
    portrait = ''
    address = obj.userextra.address
    contact = ''
    city = ''
    try:
        if obj.userextra.auth_type:
            auth_type = LOGIN_AUTH_TYPE.getDesc(obj.userextra.auth_type)

        if obj.userextra.membership_level == '1':
            membership_level = True

        if obj.userextra.city:
            city = obj.userextra.city.name
        portrait = get_full_path(obj.userextra.portrait)
        address = obj.userextra.address
        contact = obj.userextra.phone or ''  # 联系人电话
    except UserExtra.DoesNotExist:
        pass

    points = ''
    phone = ''
    try:
        points = obj.person.points
        phone = obj.person.phone or ''  # 登陆手机号
    except Person.DoesNotExist:
        pass
    old_email = u''
    if getattr(obj, 'doctor', None):
        old_email = obj.doctor.doc_email
    area = getattr(obj.person, 'area', None)
    blacklist = False if obj.userblacklist_set.count() == 0 else True
    and_filter = {
        'user_id': obj.id,
    }
    reply_num = topic_reply_filter(and_filter, is_count=True)
    # create user_classify by zoumingzhe at 18/11/13
    c_user_obj = ClassifyUser.objects.filter(user_id=obj.id, classify=USER_CLASSIFY.MODEL).first()
    user_classify = USER_CLASSIFY.getDesc(c_user_obj.classify) if c_user_obj else '普通用户'
    protect_phone = ProtectPhone.objects.filter(user_id=user_id, event_type=USERCALL_EVENT_TYPE.USER_DETAIL, is_online=True).first()
    user_data = {
        'id': str(obj.id),
        'first_name': filter_user_nick_name(obj),
        'username': obj.username,
        'last_name': obj.last_name,
        'coupon_num': obj.couponinfo_set.count(),
        'order_num': obj.order_set.count(),
        'topic_num': topic_count(obj.id),
        'diary_num': diary_count(obj.id),
        'reply_num': reply_num,
        'device_num': ','.join(device_list),
        'points_amount': points,
        'phone': phone,
        'contact': contact,
        'portrait': portrait,
        'address': escape(address),
        'auth_type': auth_type,
        'membership_level': membership_level,
        'city': city,
        'blacklist': blacklist,
        'email': obj.person.email or old_email,
        'area': area.area_name if area else u'中国',
        'person_id': obj.person.id.hex,
        'interest_college': interest_college.college_id if interest_college else '',
        'risk_score': obj.userextra.risk_score,
        'risk_result': obj.userextra.risk_result,
        'risk_check': obj.userextra.risk_check,
        'user_classify': user_classify,
        'is_bind': False if protect_phone else True,
    }
    return user_data


@bind_context(uri_pre + '/black')
def user_blacklist(ctx, items):
    info = []
    for obj in items:
        if obj['is_black']:
            user_black, _ = UserBlackList.objects.get_or_create(bind_user_id=obj['key'])
            for device in user_black.bind_user.devices.all():
                UserBlackList.objects.get_or_create(device_id=device.id)
        else:
            UserBlackList.delete_by_user_id(obj['key'])

        info.append(obj['key'])
    return info


@bind_context(uri_pre + '/unbind')
@transaction.atomic
def user_unbind(ctx, id):
    try:
        user = User.objects.get(id=id)
    except User.DoesNotExist:
        return id
    # 用户解绑
    info_logger.info('user:%s(%s)|person:%s(%s)' % (user.id, user.username, user.person.id.hex, user.person.phone))
    reset_username(user)
    user.person.phone = None
    user.person.save()
    user.userextra.phone = None
    user.userextra.save()
    return id


@bind_context(uri_pre + '/reset')
def user_reset(ctx, id, phone):
    person_list = Person.objects.filter(phone=phone).all()
    if len(person_list) == 0:
        try:
            user = User.objects.get(id=id)
        except User.DoesNotExist:
            return {'msg': u'用户不存在'}
        # 用户绑定
        user.person.phone = phone
        user.person.save()
        user.userextra.phone = phone
        user.userextra.save()
        return {'msg': u'绑定成功'}
    else:
        user_ids = set()
        if person_list:
            user_ids.add(person_list[0].user)

        msg = ''
        for id in user_ids:
            msg += str(id) + '\n'

        return {'msg': u'该手机号已被\n{}的用户绑定！请先解绑手机号再重新绑定'.format(msg)}


@bind_context(uri_pre + '/password')
def user_password(ctx, id):
    try:
        user = User.objects.get(id=id)
    except User.DoesNotExist:
        return id
    # send_sms(phone, msg, temp_id, params, is_debug=False)
    return id


@bind_context(uri_pre + '/login_code')
def user_login_code(ctx, phone):
    code = VerifiedCode.generate(phone, VERIFY_CODE_TYPE.LOGIN)
    return {"code": code}


@bind_context(uri_pre + "/create")
@transaction.atomic
def user_create(ctx, last_name, portrait='', group_name='', is_puppet=False, username=None, email=''):
    password = random_str(8)
    user = UserExtra.create_user(username or random_str(32), email, password)
    user.last_name = last_name
    if email and username:
        user.email = email
        send_user_passwd_email_v2(email, username, password)
    user.userextra.portrait = portrait
    user.userextra.save()
    user.save()
    ctx.logger.app(**user_register_log_data(user_id=user.id))
    try:
        group = BackendGroup.objects.get(name=group_name)
        group.members.add(user)
    except BackendGroup.DoesNotExist:
        pass
    person = Person.objects.create(phone=None, user=user, is_puppet=is_puppet)
    update_password(user.person, password)
    return {"person_id": person.id.hex, 'msg': '创建马甲成功', 'user_id': person.user_id}


@bind_context(uri_pre + "/validate")
def user_validate(ctx, email):
    user = User.objects.get(username=email.split('@', 1)[0])
    if user.is_staff:
        return {
            'person_id': user.person.id.hex,
        }
    raise GaiaRPCFaultException(1, u'改用户不是后台用户', data={})


@bind_context(uri_pre + "/fanlist")
def user_fanslist(ctx, options):
    dtobj = UserDQ()
    return dtobj.process(**options)


@bind_context(uri_pre + "/add_fans")
def user_addfans(ctx, user_id, fans):
    today = datetime.date.today()
    last_login = datetime.datetime(today.year - 1, today.month, today.day, 23, 59, 59)
    users_fans = UserFollow.objects.filter(follow_id=user_id).values_list('user_id', flat=True)
    users = User.objects.filter(last_login__lte=last_login).exclude(id__in=list(users_fans))[0:int(fans)]
    for user in users:
        UserFollow.objects.create(follow_id=user_id, user=user, is_virtual_fan=True)
    return {'message': 'success'}


@bind(uri_pre + '/set_addfans_config')
def addfans_config(config):
    AddFansConfig.set(config)
    return {'message': u'修改成功！'}


@bind_context(uri_pre + '/get_addfans_config')
def get_addfans_config(ctx):
    return AddFansConfig.get()


@bind_context(uri_pre + '/getinfoby_userid')
def user_getinfo_byid(ctx, user_id):
    """
    根据user_id获取用户信息
    :param ctx:
    :param user_id:
    :return:
    """
    try:
        user = User.objects.get(id=user_id)
        return {
            'id': user.id,
            'name': user.last_name if user.last_name else user.username,
            'email': user.email,
            'phone': user.person.phone
        }
    except Exception:
        logging_exception()
        raise


@bind_context(uri_pre + '/getinfoby_lastname')
def user_getinfo_by_lastname(ctx, user_name):
    """
    根据last_name获取用户信息
    :param ctx:
    :param last_name:
    :return:
    """
    try:
        users = User.objects.filter(last_name=user_name)
        if users:
            return [user.id for user in users]
        else:
            return None
    except Exception:
        logging_exception()
        return None


@bind_context(uri_pre + '/getinfoby_loginphone')
def user_getinfo_by_loginphone(ctx, login_phone):
    """
    根据loginphone获取用户信息
    :param ctx:
    :param login_phone:
    :return:
    """
    if login_phone == '':
        return {
            'error': 1
        }
    try:
        user = User.objects.get(person__phone=login_phone)
        return {
            'id': user.id,
            'name': user.last_name,
        }
    except Exception:
        logging_exception()
        return {
            'error': 1
        }


@bind_context(uri_pre + '/get_phone')
def get_user_phone(ctx, user_id, call_phone=None):
    user = get_user_from_context(ctx)

    ret = {
        "code": 0,
        "msg": '',
        "calleeNum": '',
        "callerNum": '',
    }
    if not user:
        ret['code'] = -1
        ret['msg'] = "呼叫人员信息不存在!"
        return ret
    info_logger.info({'current_user_id': user.id, 'user_id': user_id})
    try:
        callernum = UserInnerInfo.objects.get(user_id=user.id).phone
    except Exception:
        callernum = None

    try:
        if not call_phone:
            calleenum = Person.objects.get(user_id=user_id).phone
            if not calleenum:
                ret['code'] = -1
                ret['msg'] = "用户手机号不存在!"
                return ret 
        else:
            calleenum = call_phone
    except Exception:
        calleenum = None

    if all([callernum, calleenum]):
        ret['callerNum'] = callernum
        ret['calleeNum'] = calleenum
    else:
        ret['code'] = -1
        ret['msg'] = "呼叫人员或者用户手机号不存在!"

    return ret


@bind_context(uri_pre + '/upload_excel')
def upload_user(ctx, data):
    """
    上传数据
    :param ctx:
    :param data:
    :return:
    """

    resp_data = list()
    for item in data:
        sub_data = ['-'] * 4
        if not any(item):
            continue
        user_id, favor, city_id = item
        sub_data[1] = favor
        sub_data[2] = city_id
        try:
            user = User.objects.get(pk=user_id)
            if not user.person.phone:
                sub_data[-1] = "用户没有手机号"
            sub_data[0] = user.id
        except User.DoesNotExist:
            sub_data[0] = user_id
            sub_data[-1] = "用户不存在"

        if sub_data[-1] == "-":
            sub_data[-1] = "success"
        resp_data.append(sub_data)
    return resp_data


@bind_context(uri_pre + '/import_excel')
def upload_user(ctx, data):
    try:
        ProtectPhone.objects.bulk_create([ProtectPhone(user_id=d['user_id'], favor=d['favor'], city_id=d['city_id']) for d in data])
    except Exception as e:
        logging_exception()
    return "success"