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

import datetime
import json

from django.contrib.auth import authenticate, BACKEND_SESSION_KEY
from gm_types.gaia import USER_CLASSIFY, USERCALL_EVENT_TYPE
from gm_types.gaia import HERA_OPERATE_LOG_PACKAGE, HERA_OPERATE_LOG_ACTION
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, HeraProtectPhoneHuaweiyunBindingRelationship, \
    HeraProtectPhoneUserCallbackList
from api.tool.verification_code import VerifiedCode
from api.tool.image_utils import get_full_path
from api.util.user_util import _do_login
from hippo.models import Doctor
from rpc.context import Session
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 hera.audit import audit_write_log
from api.models.types import LOGIN_AUTH_TYPE
from api.models.user import UserExtra, UserExtraToCollege, UserInnerInfo, PlatformUser
from api.models.phone_protect import ProtectPhone
from api.models.person import Person
from api.util.user_util import user_is_third_party, UserCancellation
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
from api.tasks.create_fake_users import create_fake_users

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, using=getattr(settings, 'HERA_READ_DB', ''))
    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)
    query = query.using(settings.HERA_READ_DB)
    # 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)
    query = query.using(settings.HERA_READ_DB)
    # 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.using(settings.HERA_READ_DB).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:
        user_info.pop('is_good_looking', 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 ''  # 登陆手机号
        phone = phone[:3]+'*****'+phone[-3:] if phone else ''
    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,
        'is_good_looking': obj.userextra.is_good_looking,
    }
    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 + '/cancellation')
def user_cancellation(ctx, user_id):

    try:
        user = User.objects.get(id=user_id)
    except User.DoesNotExist:
        return {'msg': u'当前用户不存在'}

    user_logger.info(
        json.dumps({
            "user_id": user_id, "username": user.username,
            "person_phone": user.person.phone, "userextra_phone": user.userextra.phone,
        })
    )

    # 解绑手机号码
    reset_username(user)
    user.person.phone = None
    user.person.save()
    user.userextra.phone = None
    user.userextra.save()

    # 解绑三方账号
    try:
        plu_obj = PlatformUser.objects.get(user_id=user_id)
        platform_id = plu_obj.platform_id
        plu_obj.platform_id = platform_id + "_black_" + random_str(8)
        plu_obj.save()
    except:
        platform_id = ""

    operator = ctx.session.user
    audit_write_log(
        user=operator,
        package=HERA_OPERATE_LOG_PACKAGE.USER_CANCELLATION,
        action=HERA_OPERATE_LOG_ACTION.USER_CANCELLATION,
        object_type='user',
        object_id=user_id,
        message=json.dumps({
            "user_id": user_id, "username": user.username, "platform_id": platform_id,
            "person_phone": user.person.phone, "userextra_phone": user.userextra.phone,
        }),
    )

    UserCancellation.record_cancellation_user(user_id)

    return {'msg': u'注销成功'}


@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(uri_pre + '/check_operator_bind')
def check_operator_bind(operator_id):
    ret = {
        'code': -1
    }
    obj = HeraProtectPhoneHuaweiyunBindingRelationship.objects.filter(operator_id=operator_id).last()
    if obj:
        ret['code'] = 0
        ret['id'] = obj.id
        ret['subscription_id'] = obj.subscription_id
        ret['is_bind'] = obj.is_bind
        ret['user_id'] = obj.user_id

    return ret

@bind(uri_pre + '/get_subscriptionid')
def get_subscriptionid(protectPhone_id):
    ret = {
        'code': -1
    }
    obj = HeraProtectPhoneUserCallbackList.objects.filter(id=protectPhone_id).last()
    if obj:
        pro = HeraProtectPhoneHuaweiyunBindingRelationship.objects.filter(
            subscription_id=obj.subscription_id).last()
    if obj and pro:
        ret = {
            'code': 0,
            'bind_list_id': pro.id,
            'subscription_id': obj.subscription_id,
        }
    return ret


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

    ret = {
        "code": 0,
        "msg": '',
        "calleenum": '',
        "callernum": '',
    }
    if not operator_id:
        ret['code'] = -1
        ret['msg'] = "呼叫人员信息不存在!"
        return ret
    info_logger.info({'current_user_id': operator_id, 'user_id': user_id})
    try:
        callernum = UserInnerInfo.objects.get(user_id=operator_id).phone
        if not callernum:
            ret['code'] = -1
            ret['msg'] = "呼叫人员手机号不存在!"
            return ret
    except Exception as e:
        info_logger.info(e)
        callernum = None
        ret['code'] = -1
        ret['msg'] = "获取呼叫人员信息失败!"

    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 as e:
        info_logger.info(e)
        calleenum = None
        ret['code'] = -1
        ret['msg'] = "获取用户人员信息失败!"

    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)
            call_list_user = HeraProtectPhoneUserCallbackList.objects.filter(user_id=user_id).last()
            if call_list_user:
                sub_data[-1] = "用户回拨列表中已存在该用户"
            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:
        callbacklist = []
        for d in data:
            callbacklist.append(
                HeraProtectPhoneUserCallbackList(user_id=d['user_id'], favor=d['favor'], city_id=d['city_id']))

        HeraProtectPhoneUserCallbackList.objects.bulk_create(callbacklist)
    except Exception as e:
        logging_exception()
        return "failure" + e
    return "success"


@bind_context(uri_pre + '/business_backend_login')
def business_backend_login(ctx, username, password):
    user = User.objects.filter(username=username).first()
    if not user:
        return dict(code=1, message='用户不存在')

    auth_user = authenticate(username=username, password=password)
    if not auth_user:
        return dict(code=2, message='密码错误')

    # permission
    if not user.is_superuser:
        permissions = set()
        for group in BackendGroup.objects.filter(members=user):
            permissions.update(set(group.permissions.all()))

        find_business_visible_permission = False
        for permission in permissions:
            if permission.module.name == 'business_backend' and 'visible' == permission.name:
                find_business_visible_permission = True
                break

        if not find_business_visible_permission:
            return dict(code=3, message='没有"商务后台|可见"权限')
    data = _do_login(ctx, auth_user)
    return dict(code=0, message='ok', data={
        'session_id':data['session_key'],
        'user_id':data['login_user_id'],
        'username': auth_user.username
    })


@bind_context(uri_pre + '/business_user_info')
def business_user_info(ctx):
    user = get_user_from_context(ctx)
    print(user)
    if not user or not user.id:
        return None
    return {
        'user_id': user.id,
    }


@bind_context(uri_pre + '/business_login_doctor')
def business_login_doctor(ctx, doctor_id):
    business_user = get_user_from_context(ctx)
    if not business_user:
        return None
    if not doctor_id:
        return None
    doctor = Doctor.objects.prefetch_related('user').filter(id=doctor_id).first()
    session = Session(session_key=None)
    user = doctor.user
    user.backend = ctx.session._django_session[BACKEND_SESSION_KEY]
    session.do_login(user)
    return {
        'session_id': session.session_key,
        'user_id': user.id,
        'username': user.username
    }


@bind_context(uri_pre + '/user_create_batch')
def user_create_batch(ctx, num, to_user_emails=[]):
    to_user_emails.extend(settings.USER_CREATE_BATCH_EMIALS)
    create_fake_users.delay(list(set(to_user_emails)), num)


@bind(uri_pre + '/search')
def search_username(username=None):
    id_list = []
    if username:
        id_list = User.objects.filter(last_name__contains=username).values_list('id', flat=True)
    return list(id_list)


@bind(uri_pre + '/search/dict')
def search_user_dict(user_id_list=None):
    id_name_dict = {}
    if user_id_list:
        id_name_list = User.objects.filter(id__in=user_id_list).values_list('id','last_name')
        for id, username in id_name_list:
            id_name_dict[id] = username
    return id_name_dict


