#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/6/25

import datetime
import time

import redis
from django.conf import settings
from django.db import transaction
from django.db.models import Q
from django_bulk_update.helper import bulk_update
from gm_dataquery.dataquery import DataBuilder, DataSQLQuery
from gm_dataquery.db import DB
from gm_types.error import ERROR
from gm_types.gaia import NO_REPLY, CONSUME_PONTENTIAL, OPERATION_ACTION, SINGLE_TYPE, USER_GENDER, AssistStatus, TRANSFER_SOURCE, BD_SERVICE_TYPE

from api.models import Tag, Doctor, BDTransferWebKefu, User, BDTransferWillingProject, MerchantRelevance, Merchant, BDTransferAssist
from api.models.bd_transfer import BDTransfer, BDTransferOperationRecord, BDTransferClueTag, BDTransferSingleRecord, \
    BDTransferVisitRecord, BDTransferCommunicationRecord
from api.tool.user_tool import get_user_by_id
from rpc.exceptions import GaiaRPCFaultException
from rpc.tool.error_code import CODES, gen
from themis.views.team import recursive_users
from hera.models import UserPerm
from hera.models import BDTransferAssignRecord
from utils.time_tools import get_today_range


CONSUME_POTENTIAL_MAP = {
    CONSUME_PONTENTIAL.ZERO_THOUSAND: (0, 1000),
    CONSUME_PONTENTIAL.THOUSAND_THREE_THOUSAND: (1000, 3000),
    CONSUME_PONTENTIAL.THREE_THOUSAND_EIGHT_THOUSAND: (3000, 8000),
    CONSUME_PONTENTIAL.EIGHT_THOUSAND_FIFTH_THOUSAND: (8000, 15000),
    CONSUME_PONTENTIAL.FIFTH_THOUSAND_THRITY_THOUSAND: (15000, 30000),
    CONSUME_PONTENTIAL.THRITY_THOUSAND_PLUS: (30000, None)
}


class BdTransferDB(DataBuilder):

    def getval_consume_potential(self, obj):
        return "{0}-{1}".format(obj.consume_potential_min, obj.consume_potential_max)

    def getval_willing_cities_name(self, obj):
        return obj.get_willing_cities_name()

    def getval_willing_projects(self, obj):
        return [_.tag.name for _ in obj.willing_projects.all()]

    def getval_coupon_creator_name(self, obj):
        u = User.objects.get(id=obj.creator)
        coupon_creator_name = u.last_name if u.last_name else u.username
        if not coupon_creator_name:
            coupon_creator_name = ''
        return coupon_creator_name

    def getval_follow_up_consultant_name(self, obj):
        name = obj.current_follow_up_consultant.username
        follow_up_consultant_name = name if name else obj.current_follow_up_consultant.last_name
        if not follow_up_consultant_name:
            follow_up_consultant_name = ''
        return follow_up_consultant_name

    def getval_assist_consultants(self, obj):
        objs = BDTransferAssist.objects.filter(bdtransfer=obj, is_delete=False, status=AssistStatus.PASSED).all()
        result = []
        for obj in objs:
            assist_username = obj.assistor.username
            result.append(assist_username)
        return result

    def getval_itention_tag(self, obj):
        objs = BDTransferWillingProject.objects.filter(bdtransfer=obj).order_by('start_time')
        result = []
        for obj in objs[:3]:
            tag_obj = Tag.objects.get(id=obj.tag_id)
            result.append(tag_obj.name)
        return '、'.join(result)


@DB
class BdTransferDQ(DataSQLQuery):
    model = BDTransfer
    data_model = BdTransferDB

    def filter_assist_consultants(self, srch_key, srch_value, regex=False):
        bdtransfer_ids = BDTransferAssist.objects.filter(assistor__username=srch_value, is_delete=False, status=AssistStatus.PASSED).values_list('bdtransfer_id')
        return Q(pk__in=bdtransfer_ids)

    def filter_last_follow_time(self, srch_key, srch_value, regex=False):
        """过滤未联系时间"""
        today_wee_datetime = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
        srch_value = int(srch_value)
        if srch_value == NO_REPLY.ONE_WEEK:
            filter_string = Q(last_follow_time__gte=today_wee_datetime - datetime.timedelta(days=7))
        elif srch_value == NO_REPLY.ONE_MONTH:
            filter_string = Q(last_follow_time__gte=today_wee_datetime - datetime.timedelta(days=30))
        elif srch_value == NO_REPLY.THREE_MONTH:
            filter_string = Q(last_follow_time__gte=today_wee_datetime - datetime.timedelta(days=90))
        elif srch_value == NO_REPLY.THREE_MONTH_ABOVE:
            filter_string = Q(last_follow_time__lte=today_wee_datetime - datetime.timedelta(days=90))
        else:
            filter_string = Q()
        return filter_string

    def filter_last_follow_time_custom(self, srch_key, srch_value, regex=False):
        """过滤未联系时间自定义"""
        srch_key = u'last_follow_time'
        return self._qry_time_range(srch_key, srch_value, regex)

    def filter_consume_potential(self, srch_key, srch_value, regex=False):
        """过滤消费潜力"""
        srch_value = int(srch_value)
        lower, upper = CONSUME_POTENTIAL_MAP[srch_value]
        filter_string = Q(consume_potential_max__gt=lower)
        if upper is not None:
            filter_string &= Q(consume_potential_max__lte=upper)
        return filter_string

    def filter_create_time(self, srch_key, srch_value, regex=False):
        """过滤创建时间"""
        # return self._qry_time_range(srch_key, srch_value, regex)
        today_wee_datetime = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
        srch_value = int(srch_value)
        if srch_value == NO_REPLY.ONE_WEEK:
            filter_string = Q(create_time__gte=today_wee_datetime - datetime.timedelta(days=7))
        elif srch_value == NO_REPLY.ONE_MONTH:
            filter_string = Q(create_time__gte=today_wee_datetime - datetime.timedelta(days=30))
        elif srch_value == NO_REPLY.THREE_MONTH:
            filter_string = Q(create_time__gte=today_wee_datetime - datetime.timedelta(days=90))
        elif srch_value == NO_REPLY.THREE_MONTH_ABOVE:
            filter_string = Q(create_time__lte=today_wee_datetime - datetime.timedelta(days=90))
        else:
            filter_string = Q()
        return filter_string

    def filter_create_time_custom(self, srch_key, srch_value, regex=False):
        """过滤创建时间自定义"""
        srch_key = u'create_time'
        return self._qry_time_range(srch_key, srch_value, regex)

    def filter_single_records__single_time(self, srch_key, srch_value, regex=False):
        """过滤派单时间"""
        today_wee_datetime = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
        srch_value = int(srch_value)
        if srch_value == NO_REPLY.ONE_WEEK:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(single_time__gte=today_wee_datetime - datetime.timedelta(days=7)).values_list('dbtransfer__id', flat=True)))
        elif srch_value == NO_REPLY.ONE_MONTH:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(single_time__gte=today_wee_datetime - datetime.timedelta(days=30)).values_list('dbtransfer__id', flat=True)))
        elif srch_value == NO_REPLY.THREE_MONTH:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(single_time__gte=today_wee_datetime - datetime.timedelta(days=90)).values_list('dbtransfer__id', flat=True)))
        elif srch_value == NO_REPLY.THREE_MONTH_ABOVE:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(single_time__lte=today_wee_datetime - datetime.timedelta(days=90)).values_list('dbtransfer__id', flat=True)))
        else:
            bdtransfer_ids = []
            # return ~Q(id__in=bdtransfer_ids)
        print ('$$$$$$$$$$$$$4',bdtransfer_ids)
        return Q(id__in=bdtransfer_ids)

    def filter_single_records__single_time_custom(self, srch_key, srch_value, regex=False):
        """过滤派单时间自定义"""
        start_date = datetime.datetime.strptime(srch_value[0],'%Y-%m-%d')
        end_date = datetime.datetime.strptime(srch_value[1],'%Y-%m-%d')+datetime.timedelta(days=1)
        bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(single_time__gte=start_date, single_time__lt=end_date).values_list('dbtransfer__id', flat=True)))
        return Q(id__in=bdtransfer_ids)

    def filter_assigned_time(self, srch_key, srch_value, regex=False):
        """过滤分配时间"""
        return self._qry_time_range(srch_key, srch_value, regex)

    def filter_pooled_time(self, srch_key, srch_value, regex=False):
        """过滤分配时间"""
        return self._qry_time_range(srch_key, srch_value, regex)

    def filter_opuser(self, srch_key, srch_value, regex=False):
        """过滤个人池所能看到的转诊信息"""
        user_ids = recursive_users.func(user_id=srch_value)
        bdtransfer_ids = BDTransferAssist.objects.filter(assistor_id=srch_value, is_delete=False, status=AssistStatus.PASSED).values_list('bdtransfer_id')
        return Q(assigner__in=user_ids) | Q(pk__in=bdtransfer_ids)

    def filter_willing_city(self, srch_key, srch_value, regex=False):
        return Q(willing_cities__id=srch_value)

    def filter_single_doctor(self, srch_key, srch_value, regex=False):
        bdtransfer_ids = list(set((BDTransferSingleRecord.objects.filter(doctor_id=srch_value).
                              values_list('dbtransfer_id', flat=True))))
        return Q(id__in=bdtransfer_ids)

    def filter_has_single_record(self, srch_key, srch_value, regex=False):
        bdtransfer_ids = list(set((BDTransferSingleRecord.objects.values_list('dbtransfer_id', flat=True))))
        if bool(int(srch_value)):
            return Q(id__in=bdtransfer_ids)
        else:
            return ~Q(id__in=bdtransfer_ids)

    def filter_has_finished_single(self, srch_key, srch_value, regex=False):
        bdtransfer_ids = list(set((BDTransferSingleRecord.objects.filter(status=SINGLE_TYPE.HAS_ORDER_FORM).
                                   values_list('dbtransfer_id', flat=True))))
        if bool(int(srch_value)):
            return Q(id__in=bdtransfer_ids)
        else:
            return ~Q(id__in=bdtransfer_ids)

    def filter_creator_name(self, srch_key, srch_value, regex=False):
        from api.models.user import User
        user = User.objects.filter(username=srch_value).first()
        if not user:
            return Q(creator=-1)
        return Q(creator=user.id)


    def filter_consultation_time(self, srch_key, srch_value, regex=False):
        """面诊时间过滤"""
        today_wee_datetime = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
        srch_value = int(srch_value)
        if srch_value == NO_REPLY.ONE_WEEK:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(consultation_time__gte=today_wee_datetime - datetime.timedelta(days=7)).values_list('dbtransfer__id', flat=True)))
        elif srch_value == NO_REPLY.ONE_MONTH:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(consultation_time__gte=today_wee_datetime - datetime.timedelta(days=30)).values_list('dbtransfer__id', flat=True)))
        elif srch_value == NO_REPLY.THREE_MONTH:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(consultation_time__gte=today_wee_datetime - datetime.timedelta(days=90)).values_list('dbtransfer__id', flat=True)))
        elif srch_value == NO_REPLY.THREE_MONTH_ABOVE:
            bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(consultation_time__lte=today_wee_datetime - datetime.timedelta(days=90)).values_list('dbtransfer__id', flat=True)))
        else:
            bdtransfer_ids = []
        return Q(id__in=bdtransfer_ids)

    def filter_consultation_time_custom(self, srch_key, srch_value, regex=False):
        """自定义面诊时间过滤"""
        start_date = datetime.datetime.strptime(srch_value[0],'%Y-%m-%d')
        end_date = datetime.datetime.strptime(srch_value[1],'%Y-%m-%d')+datetime.timedelta(days=1)
        bdtransfer_ids = list(set(BDTransferSingleRecord.objects.filter(consultation_time__gte=start_date, consultation_time__lt=end_date).values_list('dbtransfer__id', flat=True)))
        return Q(id__in=bdtransfer_ids)

    @transaction.atomic
    def update(self, updates, **kwargs):
        # TODO: 用户权限的判断
        opuser_id = updates['operate_user_id']
        operation_type = int(updates.pop('type', -1))
        action = updates.pop('action', '')

        assigner_id = updates.get('assigner_id')
        assigner = get_user_by_id(assigner_id)
        opuser = get_user_by_id(opuser_id)
        if opuser is None:
            raise GaiaRPCFaultException(ERROR.USER_NOT_FOUND, u"对象商务人员不存在", data=None)

        bdtransfers = self.model.objects.select_for_update().filter(**kwargs)
        if not bdtransfers:
            raise GaiaRPCFaultException(ERROR.UNIVERSAL, u"转诊对象未找到", data=None)
        if operation_type == OPERATION_ACTION.ASSIGN:
            content = u"分配给 {}".format(assigner.username)
            updates = {"is_assign": True, "assigner": assigner_id, 'assigned_time': datetime.datetime.now(),
                       'current_follow_up_consultant': assigner, 'is_back': False, 'pooled_time': datetime.datetime.now()}
        elif operation_type == OPERATION_ACTION.RETURN:
            bdtransfer = bdtransfers[0]
            BDTransferAssist.objects.filter(bdtransfer=bdtransfer).update(is_delete=True)
            content = u"回抛原因: {}".format(updates['throw_reason'])
            updates = {"is_assign": False, "assigner": None, 'assigned_time': None,
                       'current_follow_up_consultant': None, "is_back": True, 'pooled_time': datetime.datetime.now()}
            bdtransfer.visit_records.filter(status__in=[BD_SERVICE_TYPE.TOBEDONE, BD_SERVICE_TYPE.OVERDUE]).update(status=BD_SERVICE_TYPE.INVALID)
        elif operation_type == -1:  # 暂时这样写, 后续处理
            content = u"回抛原因: {}".format("回抛池转入公池")
        else:
            raise GaiaRPCFaultException(ERROR.UNIVERSAL, u"操作类型错误", data=None)

        if action == "re_back":
            updates = {'is_back': False, 'pooled_time': datetime.datetime.now()}
        elif action == 'delete':
            BDTransfer.objects.filter(id=kwargs['id']).delete()
            return

        for bdtransfer in bdtransfers:
            if operation_type == OPERATION_ACTION.ASSIGN and any([bdtransfer.is_assign, bdtransfer.assigner]):
                raise GaiaRPCFaultException(ERROR.UNIVERSAL, u"转诊编号 {} 已经分配过".format(bdtransfer.id), data=None)
            elif operation_type == OPERATION_ACTION.RETURN and not all([bdtransfer.is_assign, bdtransfer.assigner]):
                raise GaiaRPCFaultException(ERROR.UNKNOWN_ERROR, u"转诊编号 {} 没有被分配过, 不能回抛公共池", data=None)
            for key, value in updates.items():
                setattr(bdtransfer, key, value)
        BDTransferOperationRecord.objects.bulk_create([
            BDTransferOperationRecord(
                bdtransfer=bdtransfer, action=operation_type, content=content, operate_user=opuser
            ) for bdtransfer in bdtransfers
        ])
        if operation_type == OPERATION_ACTION.ASSIGN:
            today = datetime.date.today()
            record = BDTransferAssignRecord.objects.filter(user_id=assigner_id, date=today).first()
            if not record:
                BDTransferAssignRecord.objects.create(**{'user_id':assigner_id, 'count':1, 'date':today})
            else:
                record.count = record.count + 1
                record.save()
        return bulk_update(bdtransfers, update_fields=updates.keys())


class BDTransferClueTagDB(DataBuilder):
    pass


@DB
class BDTransferClueTagDQ(DataSQLQuery):
    model = BDTransferClueTag
    data_model = BDTransferClueTagDB


class BDTransferSingleRecordDB(DataBuilder):

    def getval_projects(self, obj):
        """将对应id关联的tag_id"""
        return list(obj.project.all().values_list('id', flat=True))


    def getval_merchant_name(self, obj):
        doctor = obj.doctor
        try:
            merchant = MerchantRelevance.objects.get(doctor=doctor).merchant
            name = merchant.name
        except:
            name = ''
        return name


    def getval_dbtransfer__user_name(self, obj):
        user_name = obj.dbtransfer.user
        gender = USER_GENDER.getDesc(obj.dbtransfer.gender)
        gender = gender if gender else '未知'
        age = obj.dbtransfer.age
        if not isinstance(age, long):
            age = '年龄未知'
        return '{}({}/{})'.format(user_name, gender, age)


    def getval_projects_name(self, obj):
        return '; '.join(obj.project.all().values_list('name', flat=True))


    def getval_source(self, obj):
        return TRANSFER_SOURCE.getDesc(obj.dbtransfer.source)


    def getval_creator_name(self, obj):
        return User.objects.filter(id=obj.dbtransfer.creator).first().username


@DB
class BDTransferSingleRecordDQ(DataSQLQuery):
    model = BDTransferSingleRecord
    data_model = BDTransferSingleRecordDB


    def filter_appointment_time(self, srch_key, srch_val, regex=False):
        return self._qry_time_range(srch_key, srch_val, regex)


    def filter_consultation_time(self, srch_key, srch_val, regex=False):
        return self._qry_time_range(srch_key, srch_val, regex)


    def filter_budan__create_time(self, srch_key, srch_val, regex=False):
        return self._qry_time_range(srch_key, srch_val, regex)


    def filter_single_time(self, srch_key, srch_val, regex=False):
        return self._qry_time_range(srch_key, srch_val, regex)


    def filter_merchant_name(self, srch_key, srch_val, regex=False):
        if srch_val:
            merchant_ids = Merchant.objects.filter(name__contains=srch_val).values_list('id', flat=True)
            doctor_ids = MerchantRelevance.objects.filter(merchant_id__in=merchant_ids).values_list('doctor_id', flat=True)
            return Q(doctor_id__in=list(doctor_ids))
        return Q()



    def update(self, updates, **kwargs):
        update_single_dict = dict()
        tag_objs = []
        if updates.get('doctor'):
            try:
                doctor = Doctor.objects.get(id=updates['doctor'])
                update_single_dict['doctor'] = doctor
            except Doctor.DoesNotExist:
                gen(CODES.DOCTOR_NOT_FOUND)
        if updates.get('projects'):
            tag_objs = Tag.objects.filter(id__in=updates['projects']).all()

        if 'appointment_time' in updates:
            try:
                update_single_dict['appointment_time'] = datetime.datetime.strptime(
                    updates['appointment_time'], '%Y-%m-%d %H:%M:%S'
                ) if updates['appointment_time'] else None
            except:
                raise GaiaRPCFaultException(ERROR.PARAMS_INVALID, u"预约时间格式错误", data=None)

        if 'consultation_time' in updates:
            try:
                update_single_dict['consultation_time'] = datetime.datetime.strptime(
                    updates['consultation_time'], '%Y-%m-%d %H:%M:%S'
                ) if updates['consultation_time'] else None
            except:
                raise GaiaRPCFaultException(ERROR.PARAMS_INVALID, u"面诊时间格式错误", data=None)

        if 'operation_time' in updates:
            try:
                update_single_dict['operation_time'] = datetime.datetime.strptime(
                    updates['operation_time'], '%Y-%m-%d %H:%M:%S'
                ) if updates['operation_time'] else None
            except:
                raise GaiaRPCFaultException(ERROR.PARAMS_INVALID, u"预计手术时间格式错误", data=None)

        with transaction.atomic():
            single_record = BDTransferSingleRecord.objects.select_for_update().filter(**kwargs).first()
            #判断是否修改了派单商户
            if 'doctor' in update_single_dict:
                bdtransfer_record_cache = redis.StrictRedis(**settings.REDIS['bdtransfer_record'])
                key = "transfer_treatment_"
                current_time = datetime.datetime.now().strftime('%Y-%m-%d')
                redis_key = key + current_time
                # 原商户的派单数减一
                old_merchant_id = single_record.doctor.merchant.id
                bdtransfer_record_cache.hincrby(redis_key, old_merchant_id, -1)
                if bdtransfer_record_cache.hget(redis, old_merchant_id) and int(
                        bdtransfer_record_cache.hget(redis, old_merchant_id)) < 0:
                    bdtransfer_record_cache.hset(redis_key, old_merchant_id, 0)
                # 新商户的派单数加一
                bdtransfer_record_cache.hincrby(redis_key, doctor.merchant.id)
                # 向上取整
                expire_time = int(time.mktime(time.strptime(current_time, '%Y-%m-%d')) + 3600 * 24 - time.time()) + 1
                # 过期时间更新
                bdtransfer_record_cache.expire(redis_key, expire_time)
            for attr, value in update_single_dict.items():
                setattr(single_record, attr, value)
            # 修改single status 状态
            status = SINGLE_TYPE.NO_ORDER_FORM
            if single_record.appointment_time:
                status = SINGLE_TYPE.HAS_APPOINTMENT
            if single_record.consultation_time:
                status = SINGLE_TYPE.HAS_CONSULTATION
            setattr(single_record, 'status', status)
            update_fields = ['status'] + update_single_dict.keys()
            single_record.save(update_fields=update_fields)
            if tag_objs:
                single_record.project.clear()
                single_record.project.add(*list(tag_objs))
        return 1


class BDTransferWebKefuDB(DataBuilder):
    pass


@DB
class BDTransferWebKefuDQ(DataSQLQuery):
    model = BDTransferWebKefu
    data_model = BDTransferWebKefuDB


class BDTransferAssistDB(DataBuilder):

    def getval_assistors(self, obj):
        assists = BDTransferAssist.objects.filter(status=AssistStatus.PASSED, is_delete=False, bdtransfer=obj.bdtransfer).all()
        assistor_list = list()
        for assist in assists:
            assistor_list.append(assist.assistor.username)
        return ';'.join(assistor_list)

    def getval_apply_id(self, obj):
        return "XZ" + str(obj.create_time.year) + str(obj.create_time.month) + str(obj.id)[-3:]


@DB
class BDTransferAssistDQ(DataSQLQuery):
    model = BDTransferAssist
    data_model = BDTransferAssistDB

    def filter_opuser(self, srch_key, srch_val, regex=False):
        """过滤个人所能看到的申请信息"""

        user = User.objects.filter(id=srch_val).first()
        if UserPerm.check_perm(user, ['bdtransfer.assistor_view_all']):
            return Q()
        return Q(assistor__pk=srch_val)


class BDTransferVisitRecordDB(DataBuilder):

    def getval_has_record(self, obj):
        records = obj.communication_records.all()
        recore_ids = [str(item.id) for item in records]
        str_ = ','.join(recore_ids)
        # has_record = BDTransferCommunicationRecord.objects.filter(visit_record_id=obj.id).exists()
        return str_ if recore_ids else '否'

    def getval_create_at(self, obj):
        return obj.create_at.strftime("%Y-%m-%d %H:%M:%S")


@DB
class BDTransferVisitRecordDQ(DataSQLQuery):
    model = BDTransferVisitRecord
    data_model = BDTransferVisitRecordDB

    def filter_plan_at(self, srch_key, srch_val, regex=False):
        return self._qry_time_range(srch_key, srch_val, regex)

    def filter_visit_at(self, srch_key, srch_val, regex=False):
        return self._qry_time_range(srch_key, srch_val, regex)

    def filter_create_at(self, srch_key, srch_val, regex=False):
        return self._qry_time_range(srch_key, srch_val, regex)

    def filter_is_today(self, srch_key, srch_val, regex=False):
        if srch_val == 'true':
            today_begin, today_end = get_today_range()
            return Q(plan_at__gt=today_begin) & Q(plan_at__lt=today_end)
        return Q()

    def filter_opuser(self, srch_key, srch_val, regex=False):
        """过滤回访所能看到的转诊信息"""
        user_ids = recursive_users.func(user_id=srch_val)
        return Q(assignor__in=user_ids)
