# coding=utf-8

import json
from hashlib import md5
from django.conf import settings
from django.contrib.auth.models import User, AnonymousUser
from django.db.models import Q

from datetime import datetime, timedelta
from rpc.context import get_rpc_remote_invoker
from rpc.tool.error_code import CODES, gen
from gm_types.gaia import USER_RIGHTS_LEVEL, MEMBERSHIP_LEVEL, WRONG_DEVICE_ID, PLATFORM_CHOICES, USER_TYPE
from gm_types.gaia import CLIENT_TYPE
from gm_types.user_hierarchy import EventType
from rpc.cache import addfans_config_cache
from rpc.tool.random_tool import random_str

from api.models import (
    Person,
    UserExtra,
    DOCTOR_TYPE,
    AUTHOR_TYPE,
    )
from statistic.models import PromotionChannel
from hippo.models import Doctor, Hospital

from api.tool.image_utils import get_thumb_path
from api.tool.verification_code import generate_referral_code
from mimas.tasks import send_event_task
from api.models import ORDER_STATUS
from statistic.models import Device, DeviceIDFA

__author__ = 'leaf'


def get_social_info(user):
    social_info = None
    if user:
        from social import SocialInfo
        social_info = SocialInfo(uid=user.id)
    return social_info


def get_base_info_by_users(users):
    base_infos = []
    for user in users:
        person = user.person
        extra = user.userextra
        doctor = getattr(user, 'doctor', None)
        user_info = {
            'id': user.id,
            'user_id': user.id,
            'user_name': filter_user_nick_name(user),
            'nickname': filter_user_nick_name(user),
            'person_id': '',
            'portrait': get_thumb_path(settings.DEFAULT_PORTRAIT),
            'is_puppet': False,
            'membership_level': MEMBERSHIP_LEVEL.NORMAL,
            'current_city_id': None,
            'city_id': None,
            'constellation': None,
            'user_rights_level': USER_RIGHTS_LEVEL.V1,
            'user_level': {
                'membership_icon': settings.MEMBERSHIP_IMG[MEMBERSHIP_LEVEL.NORMAL],
                'level_icon': settings.LEVEL_IMG[USER_RIGHTS_LEVEL.V1],
                'constellation_icon': '',
            },
            'user_type': USER_TYPE.NORMAL,
            'doctor_id': '',
            'doctor_name': '',
            'doctor_portrait': '',
            'hospital_id': '',
        }
        if person:
            user_info.update({
                'person_id': person.id.hex,
                'is_puppet': person.is_puppet,
            })
        if extra:
            user_info.update({
                'portrait': extra.get_portrait(),
                'membership_level': extra.membership_level,
                'current_city_id': extra.current_city_id or None,
                'city_id': extra.city_id or None,
                'constellation': extra.constellation,
                'user_rights_level': extra.user_rights_level,
                'user_level': {
                    'membership_icon': extra.membership_icon,
                    'level_icon': extra.level_icon,
                    'constellation_icon': extra.constellation_icon,
                },
                'create_time': extra.create_time and extra.create_time.strftime('%s') or '',
            })
        if doctor:
            user_type = USER_TYPE.NORMAL
            if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
                user_type = USER_TYPE.OFFICER
            elif doctor.doctor_type == DOCTOR_TYPE.DOCTOR:
                user_type = USER_TYPE.EXPERT
            user_info.update({
                'doctor_name': doctor.name,
                'doctor_portrait': doctor.portrait,
                'user_type': user_type,
                'doctor_id': doctor.id,
                'doctor_type': doctor.doctor_type,
                'hospital_id': doctor.hospital_id,
            })
        base_infos.append(user_info)
    return base_infos


def is_tongdun_user(idfa, device_id, platform):
    """是否是请求同盾的用户。"""

    try:
        query = Q(device_id=device_id) & Q(platform=platform)
        if PLATFORM_CHOICES.ANDROID == platform:
            DeviceIDFA.objects.get(query)
            return True
        else:
            if idfa:
                query = Q(idfa=idfa)
            DeviceIDFA.objects.get(query)
            return True
    except DeviceIDFA.DoesNotExist:
        return False
    except DeviceIDFA.MultipleObjectsReturned:
        return True
    except:
        return False


def get_user_extra_by_user_id(user_id, phone=None):
    extra = None
    if user_id:
        try:
            extra = UserExtra.objects.get(user_id=user_id)
        except UserExtra.DoesNotExist:
            while True:
                referral_code = generate_referral_code(10)
                if UserExtra.objects.filter(referral_code=referral_code).exists():
                    # 如果该邀请码已经存在，则继续
                    continue
                else:
                    # 邀请码不存在，创建新的
                    extra = UserExtra.objects.create(
                        user_id=user_id, referral_code=referral_code, phone=phone)
                    break
    return extra


def filter_user_nick_name(user):
    """
    获取指定用户的昵称
    函数定义已复制到passport项目, 如需修改请联系passport负责人
    @param user:
    @return:
    """
    if not user:
        return u''

    if user.last_name:
        return user.last_name

    username = user.username
    if len(username) == 11:
        return username
    else:
        return username[:8]


def update_user_info_by_user_id(user_id, name, nick_name, phone, address, birthday, zip_code, blood_type=None):
    user_extra = get_user_extra_by_user_id(user_id)
    if user_extra:

        if name:
            user_extra.name = name
        if phone:
            user_extra.phone = phone
        if address:
            user_extra.address = address or ''

        user_extra.save()
        result = {'msg': ''}

        if zip_code:
            if not zip_code.isdigit() or len(zip_code) > 6:
                return {'msg': u'邮政编码格式错误，请输入6位数字'}
            else:
                user_extra.zip_code = zip_code
        else:
            user_extra.zip_code = ''

        if birthday:
            user_extra.birthday = birthday

        if blood_type:  # 血型
            user_extra.blood_type = blood_type

        user_extra.save()

        if user_extra.user and nick_name:
            filter_word_list = get_rpc_remote_invoker()['talos/filterWord/list']()
            filter_word_list = filter_word_list.unwrap()
            old_name = user_extra.user.last_name
            if nick_name == user_extra.user.last_name:
                pass
            elif len(nick_name.strip()) > 10:
                return {'msg': u"昵称请少于10个字:)"}
            elif User.objects.filter(last_name=nick_name).exists():
                return {'msg': u"该昵称已存在，请换一个试试:)"}
            elif any(word in nick_name for word in filter_word_list):
                return {'msg': u"昵称中含有敏感词，换一个试试"}
            elif any(keyword in nick_name for keyword in (u'医生', u'大夫', u'医院', u'咨询师', u'整形', u'美容', u'医师')):
                return {'msg': u"如果您是整形医生，请返回到个人页面点击【医生加入】，申请加入更美医生专家团队。"}
            else:
                user_extra.user.last_name = nick_name.strip()
                user_extra.user.save()
                if old_name.startswith(u'更美用户') and not nick_name.startswith(u'更美用户'):
                    event_data = send_event_task(user_id=user_id, event_type=EventType.UPDATE_NICKNAME)
                    growth_value, point_value = event_data['growth_value'], event_data['point_value']
                    submit_count = event_data['submit_count']
                    result.update({
                        'growth_value': growth_value,
                        'point_value': point_value,
                        'submit_count': submit_count,
                    })

    else:
        result = {'msg': u'设置失败', 'growth_value': 0, 'point_value': 0, 'submit_count': 0}

    return result


def get_user_from_context(ctx):
    """
    从context中获取user
    """
    return ctx.session.user if not isinstance(ctx.session.user, AnonymousUser) else None


def get_user_or_anony_from_context(ctx):
    '''
    从context中获取user
    如果没有登录则返回一个特殊的匿名用户
    '''
    if isinstance(ctx.session.user, AnonymousUser):
        return User.objects.get(pk=settings.ANONYMOUS_USER_ID)
    else:
        return ctx.session.user


def get_portrait_by_user_id(user_id):
    user_extra = get_user_extra_by_user_id(user_id)
    if user_extra and user_extra.portrait:
        portrait = get_thumb_path(user_extra.portrait)
    else:
        portrait = get_thumb_path(u'img%2Fuser_portrait.png')

    return portrait


def get_membership_level_by_user_id(user_id):
    user_extra = get_user_extra_by_user_id(user_id)
    if user_extra and user_extra.membership_level:
        return user_extra.membership_level

    return MEMBERSHIP_LEVEL.NORMAL


def get_portrait_by_user(user):
    if user.userextra and user.userextra.portrait:
        portrait = get_thumb_path(user.userextra.portrait)
    else:
        portrait = get_thumb_path(u'img%2Fuser_portrait.png')
    return portrait


def get_city_name_by_user(user):
    if user.userextra and user.userextra.city:
        return user.userextra.city.name
    else:
        return u''


def get_user_by_doctor_id(doctor_id):
    try:
        doctor = Doctor.objects.get(id=doctor_id)
        return doctor.user
    except Doctor.DoesNotExist:
        return None


def get_doctor_by_user_id(user_id):
    """get doctor by user id."""
    if not user_id:
        return None  # protect ourselves

    try:
        doctor = Doctor.objects.get(user__id=user_id)
        return doctor
    except Doctor.DoesNotExist:
        return None


def get_doctor_id_by_user_id(user_id):
    doctor = get_doctor_by_user_id(user_id)
    if doctor:
        doctor_id = doctor.id
    else:
        doctor_id = ""
    return doctor_id

def get_doctor_by_user_ids(user_ids):
    """get doctor by user ids."""

    if not user_ids:
        return []

    try:
        doctors = Doctor.objects.filter(user_id__in=user_ids)
        return doctors
    except Doctor.DoesNotExist:
        return []


def get_user_city_tagid(user_id):
    extra = get_user_extra_by_user_id(user_id)
    if extra and extra.city:
        city_tagid = extra.city.tag_id
    else:
        city_tagid = None

    return city_tagid


def get_user_by_id(user_id):
    try:
        user = User.objects.get(id=user_id)
        return user
    except User.DoesNotExist:
        return None

def get_user_by_user_ids(user_ids):
    """get user by user ids."""

    if not user_ids:
        return []

    return User.objects.filter(id__in=user_ids)


def get_username_with_title(user_id):
    user = get_user_by_id(user_id)
    if not user:
        return u''

    if user.id == 22:
        return user.last_name

    try:
        doctor = Doctor.objects.get(user=user)

        if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
            who = doctor.name

        else:
            who = u'{} 医生'.format(doctor.name)

    except Doctor.DoesNotExist:
        who = user.last_name

    return who


def get_doctor_from_context(ctx):
    user = get_user_from_context(ctx)
    if user:
        return get_doctor_by_user_id(user.id)
    else:
        return None


def get_doctor_from_context_or_exception(ctx):
    d = get_doctor_from_context(ctx)
    return d if d else gen(CODES.DOCTOR_NOT_FOUND)


def get_auth_type_by_userid(user_id):
    r = get_user_type_id(user_id)

    if r['doctor_id'] or r['hospital_id']:
        return AUTHOR_TYPE.DOCTOR

    return AUTHOR_TYPE.USER


def get_user_type_id(user_id):
    """
    通过用户的id获取用户其他类型(医生 医院)的id
    """
    user = get_user_by_id(user_id)
    result = {
        'user_id': user_id,
        'hospital_id': '',
        'doctor_id': '',
    }

    if not user:
        return result

    doctor = get_doctor_by_user_id(user.id)
    if (doctor and doctor.is_online and
            doctor.doctor_type == DOCTOR_TYPE.OFFICER):
        result['hospital_id'] = doctor.hospital.id
    if (doctor and doctor.is_online and
            doctor.doctor_type == DOCTOR_TYPE.DOCTOR):
        result['doctor_id'] = doctor.id

    return result


def get_user_type_ids(user_ids):
    """
    通过用户的ids获取用户其他类型(医生 医院)的id
    """

    result = {}

    doctors = get_doctor_by_user_ids(user_ids)
    for doctor in doctors:
        item = {
            'user_id': doctor.user_id,
            'hospital_id': '',
            'doctor_id': doctor.id,
        }
        if (doctor and doctor.is_online and
                doctor.doctor_type == DOCTOR_TYPE.OFFICER):
            item['hospital_id'] = doctor.hospital.id
        if (doctor and doctor.is_online and
                doctor.doctor_type == DOCTOR_TYPE.DOCTOR):
            item['doctor_id'] = doctor.id

        result[str(doctor.user_id)] = item

    return result


def user_register_log_data(user_id):
    return {
        'is_register': True,    # 兼容地产生旧日志, 未来可考虑删掉
        'user_register_info': {
            'user_id': user_id,
        },
    }


def get_hospital_by_id(hospital_id):
    try:
        hospital = Hospital.objects.get(id=hospital_id)
        return hospital
    except Hospital.DoesNotExist:
        return None


def get_user_level(user, use_new_level_icon=False):
    if not hasattr(user, 'userextra'):
        return {
            'membership_icon': settings.MEMBERSHIP_IMG[MEMBERSHIP_LEVEL.NORMAL],
            'level_icon': settings.NEW_LEVEL_IMG[USER_RIGHTS_LEVEL.V1] if use_new_level_icon else \
            settings.LEVEL_IMG[USER_RIGHTS_LEVEL.V1],
            'constellation_icon': '',
        }
    new_user_level = settings.NEW_LEVEL_IMG[user.userextra.user_rights_level]
    old_user_level = user.userextra.level_icon if user.userextra.level_icon else ''

    return {
        'membership_icon': user.userextra.membership_icon if user.userextra.membership_icon else '',
        'level_icon': new_user_level if use_new_level_icon else old_user_level,
        'constellation_icon': user.userextra.constellation_icon if user.userextra.constellation_icon else '',
    }


class AddFansConfig(object):
    """
    粉丝增益
    """
    key = 'addfans_config'
    default_config = {
        'qa': {  # 当日有回答被选为精华
            'qa_min': 0,
            'qa_max': 20,
        },
        'talent': {  # 达人当日有登录app
            'talent_min': 10,
            'talent_max': 30,
        },
        'diary_a': {  # 日记被评为优秀
            'diary_a_min': 50,
            'diary_a_max': 150,
        },
        'diary_b': {  # 日记被评为良好
            'diary_b_min': 20,
            'diary_b_max': 50,
        },
        'diary_c': {  # 日记被评为其它
            'diary_c_min': 0,
            'diary_c_max': 20,
        },
        'topic': {  # 当日帖子收到评论
            'topic_min': 0,
            'topic_max': 10,
        }
    }

    @classmethod
    def get(cls):
        try:
            config = json.loads(addfans_config_cache.get(cls.key))
        except:
            config = cls.default_config
        return config

    @classmethod
    def set(cls, new_config):
        if not new_config:
            return

        config = cls.get()
        for k, v in new_config.items():
            if k in config:
                config[k] = v

        try:
            addfans_config_cache.set(cls.key, json.dumps(config))
        except:
            addfans_config_cache.error(u'粉丝增益配置失败')


def generate_random_nick_name():
    nick_name = u'更美用户%s' % (random_str(10))
    return nick_name


def get_user_and_payment_info(user=None, platform=None, device_id=None):
    user_payment_info = {
        'is_new_user': False,
        'have_payment': True
    }

    user_type_info = is_new_user_local(user=user, platform=platform, device_id=device_id)
    if user_type_info and user_type_info['is_new_user']:
        user_payment_info.update({'is_new_user': True})

    user_id = user.id if user else None
    if not user_have_payment(user_id=user_id):
        user_payment_info.update({'have_payment': False})

    return user_payment_info


def user_have_payment(user_id=None):
    """
        如果user_id不存在，就认为没有支付
    """
    from api.models.order import Order

    if user_id:
        result = Order.objects.filter(user_id=user_id).exclude(
            status__in=(ORDER_STATUS.CANCEL, ORDER_STATUS.NOT_PAID)
        ).exists()
    else:
        result = False  # 如果用户没有登录，那么认为没有支付
    return result


def is_new_user_local(user, platform, device_id,
                      old_user_reg_day=settings.OLD_USER_REG_MIN_DAY):

    result = {'is_new_user': False}

    if in_new_user_whitelist(user):
        result['is_new_user'] = True
        return result

    if device_id in WRONG_DEVICE_ID:
        return result

    device = Device.objects.filter(platform=platform, device_id=device_id).first()
    if not device:
        return result

    created_time = device.created_time
    new_user_time = datetime.now() - timedelta(old_user_reg_day)
    if created_time and created_time > new_user_time:
        result['is_new_user'] = True

    if user:
        # 登陆时候
        register_time = user.date_joined
        if register_time and register_time > new_user_time:
            result['is_new_user'] = True
        else:
            result['is_new_user'] = False

    return result


def get_user_by_username(username):
    try:
        user = User.objects.get(username=username)
        return user
    except User.DoesNotExist:
        return None


def is_new_service_user(user, old_user_reg_day=settings.OLD_USER_REG_MIN_DAY):
    # 未登录默认新用户
    if not user:
        return True

    if in_new_user_whitelist(user):
        return True

    from api.models.order import Order
    # 有已支付，不是新用户
    if Order.objects.filter(user_id=user.id).exclude(status__in=(ORDER_STATUS.CANCEL, ORDER_STATUS.NOT_PAID)).exists():
        return False
    # 没有已支付时，注册时间大于等于三天，不是新用户
    new_user_time = datetime.now() - timedelta(old_user_reg_day)
    register_time = user.date_joined
    if register_time and register_time <= new_user_time:
        return False
    return True


def in_new_user_whitelist(w_user):
    if not w_user:
        return False

    user_id = None
    if type(w_user) is User:
        user_id = w_user.id
    else:
        user_id = w_user
    return user_id in settings.NEW_USER_WHITE_LIST


def is_merchant_user(user):
    is_doctor = Doctor.objects.filter(user=user).exists()
    is_puppet = Person.objects.filter(user=user, is_puppet=True).exists()
    return is_doctor or is_puppet

def is_new_user_service_home(user):
    '''
    是否为新用户
    :param user:
    :return:
    '''
    from api.models import Order
    HAS_BOUGHT = (ORDER_STATUS.PAID, ORDER_STATUS.USED, ORDER_STATUS.SETTLED, ORDER_STATUS.REFUNDED, ORDER_STATUS.WAIT_REFUNDED)
    s_timeout = timedelta(seconds=settings.SETTLEMENT_SOFT_TIMEOUT)  # 未支付的超时时间
    h_timeout = timedelta(seconds=settings.SETTLEMENT_HARD_TIMEOUT)  # 付款中的超时时间
    s_expire_end_time = datetime.now() - s_timeout
    h_expire_end_time = datetime.now() - h_timeout
    order_objs = Order.objects.filter(
        Q(user=user),
        Q(status__in=HAS_BOUGHT) |
        Q(status=ORDER_STATUS.NOT_PAID, created_time__gte=s_expire_end_time) |
        Q(status=ORDER_STATUS.PAYING, created_time__gte=h_expire_end_time)
    )
    if order_objs.exists():
        return False
    return True


def new_get_user_and_payment_info(user=None, platform=None, device_id=None):
    """
    判断是否为当日新激活、有无历史支付用户
    :param user:
    :param platform:
    :param device_id:
    :return:
    """
    user_payment_info = {
        'is_new_user': False,
        'have_payment': False
    }
    user_id = user.id if user else None
    if user_id:
        from api.models import Order
        result = Order.objects.filter(user_id=user_id).exclude(pay_time=None).exists()
        user_payment_info['have_payment'] = result
    if device_id in WRONG_DEVICE_ID:
        return user_payment_info
    device = Device.objects.filter(platform=platform, device_id=device_id).first()
    if not device:
        user_payment_info['is_new_user'] = True
        return user_payment_info
    create_time = device.created_time
    now = datetime.now()
    if not create_time or now.date() == create_time.date():
        user_payment_info['is_new_user'] = True
    return user_payment_info