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

import datetime
import random
import re

from django.utils import timezone

from api.models import (
    Doctor,
    User,
    YoungDoctorApplicationForm,
    YoungDoctorCase,
    Person,
    ANTI_BRUTE_TYPE,
    DoctorRegisterInfo,
    Service,
    Special,
)


from api.tool.user_tool import get_user_from_context, filter_user_nick_name, get_portrait_by_user
from api.tool.verification_code import anti_brute, VerifiedCode
from doctor.models import DoctorRegister
from rpc.cache import yd_vote

from rpc.context import get_rpc_remote_invoker
from rpc.decorators import bind, bind_context
from rpc.tool.error_code import gen, CODES
from rpc.tool.log_tool import info_logger
from api.tool.datetime_tool import get_seconds_left_to_end_of_day, get_timestamp_or_none

from gm_types.gaia import (
    YOUNGDOCTOR_APPLY_TYPE,
    YOUNGDOCTOR_CASE_TYPE,
    DOCTOR_TYPE,
    VERIFY_CODE_TYPE,
    FILTER_WORD_TYPE,
)


@bind_context('api/activity/youngdoctor_apply', login_required=False)
def youngdoctor_apply(ctx, phone, verification_code='', pwd=''):
    """
    青年医生报名接口（含登陆）
    """
    if anti_brute(phone + ANTI_BRUTE_TYPE.LOGIN_PHONE):
        return gen(CODES.USER_MAX_RETIES)

    if pwd:
        verify = verify_with_pwd(phone, pwd)
    else:
        verify = VerifiedCode.verify(
            verification_code, phone=phone,
            code_type=VERIFY_CODE_TYPE.ACTIVITY_APPLY
        )

    if not verify:
        return gen(CODES.INVALID_CODE)

    application_form, created = YoungDoctorApplicationForm.objects.get_or_create(
        phone=phone,
    )

    result = {
        'apply_type': YOUNGDOCTOR_APPLY_TYPE.NOT_DOCTOR,
        'session': '',
    }
    user = None
    try:
        person = Person.objects.get(phone=phone)
        user = person.user
        if not user.is_active:
            user = None
    except Person.DoesNotExist:
        pass

    try:
        doctorregisterinfo = DoctorRegisterInfo.objects.filter(phone=phone)
        doctorregister = DoctorRegister.objects.filter(phone=phone)
        if not doctorregisterinfo and not doctorregister:
            raise DoctorRegisterInfo.DoesNotExist

        doctor = Doctor.objects.get(user__person__phone=phone, is_online=True)
    except DoctorRegisterInfo.DoesNotExist:
        if user and hasattr(user, 'doctor'):
            doctor = user.doctor
            pass
        else:
            return result
    except Doctor.DoesNotExist:
        result['apply_type'] = YOUNGDOCTOR_APPLY_TYPE.REGISTERED
        return result

    if not user:
        return result

    if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        application_form.doctor_type = YOUNGDOCTOR_APPLY_TYPE.OFFICER
        result['apply_type'] = YOUNGDOCTOR_APPLY_TYPE.OFFICER
        return result

    else:
        application_form.doctor_type = YOUNGDOCTOR_APPLY_TYPE.DOCTOR
        result['apply_type'] = YOUNGDOCTOR_APPLY_TYPE.DOCTOR

    if created:
        application_form.save()

    user.backend = "django.contrib.auth.backends.ModelBackend"
    ctx.session.do_login(user)
    result['session'] = ctx.session.session_key
    return result


@bind_context('api/activity/update_youngdoctor_case', login_required=True)
def update_case(ctx, type_list=[]):
    """
    更新青年医生案例品类
    """
    user = get_user_from_context(ctx)
    result = {}
    doctor = user.doctor if hasattr(user, 'doctor') else None
    if not doctor or not type_list or doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        return gen(CODES.DOCTOR_NOT_FOUND)

    real_typelist = []

    # 原来上传过案例的医生，则不允许其修改（增删改）案例
    doctor_cases = YoungDoctorCase.objects.filter(doctor=doctor)
    if doctor_cases and datetime.date.today() > datetime.date(2016, 8, 15):
        return result

    for case_type in type_list:
        if not YOUNGDOCTOR_CASE_TYPE.__contains__(case_type):
            continue

        real_typelist.append(case_type)
        yd_case, created = YoungDoctorCase.objects.get_or_create(
            doctor=doctor, case_type=case_type
        )
        yd_case.doctor_name = doctor.name
        yd_case.is_online = True
        yd_case.save()

    if not real_typelist:
        return result

    cases = YoungDoctorCase.objects.filter(doctor=doctor).exclude(case_type__in=real_typelist)
    for case in cases:
        case.is_online = False
        case.last_modified_time = timezone.now()
        case.save()

    return result


@bind_context('api/activity/get_youngdoctor_case', login_required=True)
def get_case(ctx):
    """
    青年医生大赛获取医生案例
    """
    user = get_user_from_context(ctx)
    result = {
        'cases': []
    }
    doctor = user.doctor if hasattr(user, 'doctor') else None
    if not doctor or doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        return gen(CODES.DOCTOR_NOT_FOUND)

    cases = YoungDoctorCase.objects.filter(doctor=doctor, is_online=True)
    for case in cases:
        result['cases'].append(case.to_dict())
    return result


@bind_context('api/activity/upload_youngdoctor_case', login_required=True)
def upload_case(ctx, case_type, preoperartion_front_image, preoperartion_side_image,
                postoperartion_front_image, postoperartion_side_image, description):
    """
    青年医生大赛上传案例
    """
    user = get_user_from_context(ctx)
    result = {}
    doctor = user.doctor if hasattr(user, 'doctor') else None
    if not doctor or doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        return gen(CODES.DOCTOR_NOT_FOUND)

    if not YOUNGDOCTOR_CASE_TYPE.__contains__(case_type):
        return gen(CODES.PARAMS_INVALID)

    content = description.strip()
    filter_words = get_rpc_remote_invoker()['talos/filterWord/list'](
            filter_type=FILTER_WORD_TYPE.TOPIC_REPLY
        )
    filter_words = filter_words.unwrap()
    if re.findall('\d{7,}', description) or any(word in description for word in filter_words):
        return gen(CODES.TOPIC_CONTENT_CAN_NOT_CONTAIN_CONTACT)

    elif not content:
        return gen(CODES.TOPIC_CONTENT_CAN_NOT_BE_EMPTY)

    try:
        case = YoungDoctorCase.objects.get(
            doctor=doctor, case_type=case_type, is_online=True
        )
        if datetime.date.today() > datetime.date(2016, 8, 15) and case.preoperartion_side_image:
            return result
        case.preoperartion_front_image = preoperartion_front_image
        case.preoperartion_side_image = preoperartion_side_image
        case.postoperartion_front_image = postoperartion_front_image
        case.postoperartion_side_image = postoperartion_side_image
        case.description = content
        case.last_modified_time = timezone.now()
        case.save()
    except:
        return gen(CODES.PARAMS_INVALID)

    return result


@bind_context('api/activity/young_doctor/vote')
def young_doctor_vote(ctx, openid=None, case_id=None):
    """
    青年医生大赛，投票
    """
    result = {
        'code': 0,
        'msg': u'投票成功',
        'vote_num': 0,
    }

    if not openid or not case_id:
        result['code'] = -1
        result['msg'] = u'请用微信打开，选择案例'
        return result

    vote_key = str(case_id)
    vote_real_key = '{}:real'.format(vote_key)
    vote_limit_key = "vote_limit:%s:%s" % (openid, datetime.datetime.today().strftime('%y%m%d'))
    user_vote_num = yd_vote.scard(vote_limit_key)

    # 只用一次，错误代码暂不加入gm-type
    if yd_vote.sismember(vote_limit_key, str(case_id)):
        result['msg'] = u'您今天已经投过此案例'
        result['code'] = 1
        return result

    if user_vote_num == 0:
        yd_vote.sadd(vote_limit_key, case_id)
        yd_vote.expire(vote_limit_key, get_seconds_left_to_end_of_day())
    elif user_vote_num >= 30:
        result['msg'] = u'今天投票次数已经达到上限'
        result['code'] = 2
        return result
    else:
        yd_vote.sadd(vote_limit_key, case_id)

    yd_vote.incr(vote_key, random.randint(1, 10))
    yd_vote.incr(vote_real_key, 1)
    yd_vote.sadd(vote_limit_key, case_id)
    result['vote_num'] = yd_vote.get(vote_key)

    return result


@bind_context('api/activity/young_doctor/get_cases_for_vote')
def young_doctor_get_case_for_vote(ctx, case_type=None, case_ids=[]):
    """
    青年医生大赛，获得投票案例信息
    """
    res = {'case_ids': []}
    if case_type is not None:
        case_key = 'case_cache:{}'.format(case_type)
        case_ids = list(yd_vote.lrange(case_key, 0, -1))[:10000]
        res['case_ids'] = case_ids
        res['part_case_info'] = get_case_info(case_ids[:20], with_doctor_info=True)
    else:
        res['part_case_info'] = get_case_info(case_ids, with_doctor_info=True)

    return res


@bind_context('api/activity/young_doctor/search')
def young_doctor_search(ctx, name=''):
    """
    青年医生大赛，搜索医生
    """
    if not name:
        return []

    res = []
    doctor_ids = YoungDoctorCase.objects.filter(
        doctor_name__startswith=name,
        is_online=True
    ).exclude(description='').values_list('doctor', flat=True).distinct()

    for d in Doctor.objects.filter(id__in=doctor_ids):
        res.append(
            {
                'name': d.name,
                'id': d.id,
                'hospital': d.hospital.name if d.hospital else '' if hasattr(d, 'hospital') else '',
            }
        )
    return res


@bind_context('api/activity/young_doctor/get_doctor_vote_detail')
def young_doctor_get_doctor_vote_detail(ctx, doctor_id=''):
    """
    青年医生大赛， 医生投票详情页
    """
    try:
        doctor = Doctor.objects.get(id=doctor_id)
    except Doctor.DoesNotExist, Doctor.MultipleObjectsReturned:
        return gen(CODES.DOCTOR_NOT_FOUND)

    res = {}
    case_ids = list(YoungDoctorCase.objects.filter(
        doctor=doctor,
        is_online=True,
    ).exclude(description='').values_list('id', flat=True))
    res['case_info'] = get_case_info(case_ids, with_doctor_info=False)
    res['doctor'] = {
        'name': doctor.name,
        'title': doctor.title,
        'hospital': doctor.hospital.name if doctor.hospital else '' if hasattr(doctor, 'hospital') else '',
        'image': doctor.portrait or '',
    }
    return res


def get_case_info(case_ids, with_doctor_info=False):
    res = []
    if not case_ids:
        return res

    item = {}
    for c in YoungDoctorCase.objects.filter(
            id__in=case_ids,
            is_online=True,
    ).exclude(description=''):
        item[str(c.id)] = c

    for c in case_ids:
        case = item.get(str(c), '')
        if not case:
            continue
        case_info = {
            'id': case.id,
            'name': YOUNGDOCTOR_CASE_TYPE.getDesc(case.case_type),
            'preoperation_front': case.preoperartion_front_image,
            'preoperation_side': case.preoperartion_side_image,
            'postoperation_front': case.postoperartion_front_image,
            'postoperation_side': case.postoperartion_side_image,
            'description': case.description,
            'vote_num': yd_vote.get(str(c)) or 0,
        }

        if with_doctor_info:
            try:
                case_info['doctor'] = {
                    'name': case.doctor.name,
                    'title': case.doctor.title,
                    'hospital': case.doctor.hospital.name if case.doctor.hospital else ''
                    if hasattr(case.doctor, 'hospital') else '',
                    'image': case.doctor.portrait,
                }
            except:
                pass

        res.append(case_info)

    return res


def verify_with_pwd(phone, pwd):
    try:
        person = Person.objects.get(phone=phone)
        if not person.user.password:
            return gen(CODES.PLEASE_RESET_PASSWORD)

        if person.user.check_password(pwd.strip()):
            return True

        return False

    except Person.DoesNotExist:
        return gen(CODES.PERSON_NOT_FOUND)


def get_internal_expert_case():
    key = 'white list:'
    return yd_vote.lrange(key, 0, -1)


@bind_context('api/activity/young_doctor/internal_vote')
def young_doctor_get_doctor_vote_detail(ctx, case_id='', vote_num=0):
    """
    青年医生 内部投票接口
    """
    if not case_id or not vote_num:
        return {
            'error': 1,
            'msg': u'case_id, 或者vote_num为空'
        }

    user = get_user_from_context(ctx)
    if not user or not yd_vote.sismember('internal_user', user.id):
        return {
            'error': 2,
            'msg': u'未授权用户'
        }

    if case_id not in get_internal_expert_case():
        return {
            'error': 3,
            'msg': u'case_id 不在白名单中'
        }

    vote_key = str(case_id)
    vote_before = yd_vote.get(vote_key)
    yd_vote.incr(vote_key, vote_num)
    vote_after = yd_vote.get(vote_key)
    info_logger.info('user_id: {}, case_id: {}, vote_num: {}, vote_befor: {}, vote_after: {}'.format(
        user.id,
        case_id,
        vote_num,
        vote_before,
        vote_after
    ))

    if int(vote_after) <= 0:
        yd_vote.set(vote_key, 0)
        vote_after = 0

    return {
        'error': 0,
        'msg': u'成功',
        'data': {
            'case_id': case_id,
            'vote_num': vote_num,
            'vote_before': vote_before,
            'vote_after': vote_after
        }

    }


@bind_context('api/activity/young_doctor/internal_get_vote_info')
def young_doctor_get_doctor_vote_detail(ctx):
    """
    青年医生 内部 获取白名单医生投票信息
    """

    user = get_user_from_context(ctx)
    if not user or not yd_vote.sismember('internal_user', user.id):
        return {
            'error': 2,
            'msg': u'未授权用户',
            'data': []
        }

    res = {
        'error': 0,
        'msg': '',
        'data': []
    }
    case_ids = get_internal_expert_case()

    cases_info = YoungDoctorCase.objects.filter(id__in=case_ids, is_online=True).values(
        'id',
        'doctor_id',
        'doctor_name',
        'case_type'
    )

    for info in cases_info:
        res['data'].append(
            {
                'case_id': info['id'],
                'doctor_id': info['doctor_id'],
                'vote': yd_vote.get(str(info['id'])) or '',
                'case_info': ':'.join([YOUNGDOCTOR_CASE_TYPE.getDesc(info['case_type']), info['doctor_name']])
            }
        )

    return res


@bind('api/journey/user/header')
def get_journey_user_header(user_id):
    user = User.objects.get(id=user_id)
    return {
        "user_name": filter_user_nick_name(user),
        "user_portrait": get_portrait_by_user(user),
        "time": user.date_joined.strftime('%Y-%m-%d %H:%M:%S'),
        "city": user.userextra.city.name if user.userextra.city else '',
        "user_id": user_id
    }


@bind('api/journey/service/info')
def get_journey_service_info(service_id):
    service = Service.objects.get(id=service_id)
    if service.is_multiattribute:
        price = service.gengmei_price_display.split('-')[0]
    else:
        price = service.gengmei_price_display
    return {
        "pic": service.image_header,
        "name": service.show_name,
        "price": price,
        "id": service.id,
        "is_multiattribute": service.is_multiattribute
    }


@bind('api/journey/special/list')
def get_journey_special_list(special_ids):
    specials = Special.objects.filter(id__in=special_ids)
    result = []
    for special in specials:
        result.append({
            "id": special.id,
            "banner": special.image
        })
    return result
