# -*- coding: UTF-8 -*-
import json
from django.db.models import Max, F, Q
from gm_dataquery.dataquery import DataBuilder, DataSQLQuery
from gm_dataquery.db import DB
from gm_dataquery.dict_mixin import to_dict
from gm_types.gaia import BUDAN_STATUS
from themis.models import Team
from django.contrib.auth.models import User

from api.models import Order, ORDER_STATUS, Service, Hospital, Special, ProtectPhone, User
from hippo.models import Doctor
from gm_types.gaia import SERVICE_SELL_TYPE, OPERATION_LOCATION_TYPE, COUPON_TYPES
from ..models import UserPerm
from ..utils import check_business, check_operate, operate_business, get_business_team
from api.tool.user_tool import filter_user_nick_name

from gm_types.gaia import USERCALL_EVENT_TYPE, USERCALL_STATUS


class OrderDB(DataBuilder):
    def getval_service__doctor__name(self, obj):
        return obj.service.doctor.name if obj.service.doctor else ''

    def getval_service__name(self, obj):
        return obj.servicesnapshot.name

    def getval_service__service_type_desc(self, obj):
        return SERVICE_SELL_TYPE.getDesc(obj.service.service_type)

    def getval_base_service_type(self, obj):
        return obj.service.service_type

    def getval_call_time(self, obj):
        ret = ProtectPhone.objects.filter(event_id=obj.id, event_type=USERCALL_EVENT_TYPE.ORDER_CHECK).last()
        return ret.bind_time.strftime('%Y-%m-%d %H:%M:%S') if ret else ''

    def getval_call_status(self, obj):
        ret = ProtectPhone.objects.filter(event_id=obj.id, event_type=USERCALL_EVENT_TYPE.ORDER_CHECK).last()
        return '已绑定' if ret and ret.is_online and ret.bind_time else '暂无绑定'

    def getval_call_result(self, obj):
        return USERCALL_STATUS.getDesc(obj.call_result)

    def getval_is_bind(self, obj):
        ret = ProtectPhone.objects.filter(event_id=obj.id, event_type=USERCALL_EVENT_TYPE.ORDER_CHECK).last()
        return 1 if ret and ret.bind_time and ret.is_online else 0

    def getval_bind_operator(self, obj):
        ret = ProtectPhone.objects.filter(event_id=obj.id, event_type=USERCALL_EVENT_TYPE.ORDER_CHECK).last()
        user = User.objects.filter(id=ret.operator).first()
        return filter_user_nick_name(user)

    def getval_service__doctor__hospital__name(self, obj):
        return obj.service.doctor.hospital.name if obj.service.doctor.hospital.name else ''

    def getval_service__doctor__hospital__city__name(self, obj):
        return obj.service.doctor.hospital.city.name or ''

    def getval_service__gengmei_price(self, obj):
        if obj.service.is_multiattribute:
            return obj.service.items.aggregate(gm=Max('gengmei_price')).get('gm')
        else:
            return obj.service.gengmei_price if obj.service else ''

    def getval_service__payment_type(self, obj):
        return obj.service.payment_type if obj.service else ''

    def getval_payment_type_text(self, obj):
        return obj.service.payment_type_text if obj.service else ''

    def getval_service__id(self, obj):
        return obj.service.id if obj.service else ''

    def getval_service__hospital(self, obj):
        return obj.service.doctor.hospital.id if obj.service.doctor.hospital else ''

    def getval_service__doctor__id(self, obj):
        return obj.service.doctor.id if obj.service.doctor else ''

    def getval_user__last_name(self, obj):
        return obj.user.last_name if obj.user else ''

    def getval_multiattr_items_name(self, obj):
        return obj.servicesnapshot.items

    def getval_gengmei_price(self, obj):
        return obj.servicesnapshot.gengmei_price

    def getval_pre_payment_price(self, obj):
        return obj.servicesnapshot.pre_payment_price

    def getval_refund_price(self, obj):
        return obj.refund.fee or obj.payment

    def getval_status(self, obj):
        return ORDER_STATUS.getDesc(obj.status)

    def getval_doctor(self, obj):
        return obj.servicesnapshot.doctor.name

    def getval_hospital(self, obj):
        return obj.servicesnapshot.hospital.name

    def getval_phone(self, obj):
        return obj.phone_crypt

    def getval_settle_price(self, obj):
        return obj.settle_data()['settle_payment']

    def getval_order_to_service(self, obj):
        if obj.is_ordertoservice:
            return u'已转服务'
        else:
            return u'待转服务'

    def getval_login_phone(self, obj):
        return obj.user.person.phone

    def getval_pay_business_partner(self, obj):
        return getattr(real_partner(obj.servicesnapshot.doctor, obj.pay_time), 'username', '')

    def getval_validate_business_partner(self, obj):
        op_doc = getattr(obj.operate_user, 'doctor', None)
        return getattr(real_partner(op_doc, obj.validate_time), 'username', '')

    def getval_coupon_id(self, obj):
        coupon_info = {x['coupon_type']: x for x in obj.get_order_coupon_infos()}
        return coupon_info.get(COUPON_TYPES.PLATFORM, {}).get('coupon_info_id', '')

    def getval_coupon_gengmei_value(self, obj):
        coupon_info = {x['coupon_type']: x for x in obj.get_order_coupon_infos()}
        return coupon_info.get(COUPON_TYPES.PLATFORM, {}).get('coupon_gengmei_value', 0)

    def getval_coupon_doctor_value(self, obj):
        coupon_info = {x['coupon_type']: x for x in obj.get_order_coupon_infos()}
        return coupon_info.get(COUPON_TYPES.PLATFORM, {}).get('coupon_doctor_value', 0)

    def getval_gengmei_coupon_id(self, obj):
        # 预付款券
        coupon_info = {x['coupon_type']: x for x in obj.get_order_coupon_infos()}
        return coupon_info.get(COUPON_TYPES.PLATFORM, {}).get('coupon_id', '')

    def getval_doctor_coupon_id(self, obj):
        # 尾款券
        coupon_info = {x['coupon_type']: x for x in obj.get_order_coupon_infos()}
        return coupon_info.get(COUPON_TYPES.DOCTOR, {}).get('coupon_id', '')

    def getval_gengmei_coupon_value(self, obj):
        # 预付款券抵扣金额
        coupon_info = {x['coupon_type']: x for x in obj.get_order_coupon_infos()}
        return coupon_info.get(COUPON_TYPES.PLATFORM, {}).get('platform_coupon_deduction', '')

    def getval_group(self, obj):
        doctor = obj.service.doctor
        if doctor.business_group:
            team = Team.objects.filter(id=doctor.business_group).first()
            group = team.name if team else ''
        else:
            group = ''
        return group

    def getval_operation_location(self, obj):
        if obj.operation_location_type == OPERATION_LOCATION_TYPE.WHITE_LIST:
            try:
                operation_location = Hospital.objects.get(id=obj.operation_hospital_id).name
            except:
                operation_location = obj.operation_hospital_id
        else:
            operation_location = OPERATION_LOCATION_TYPE.getDesc(obj.operation_location_type)
        return operation_location

    def getval_doctor_coupon_value(self, obj):
        coupon_info = {x['coupon_type']: x for x in obj.get_order_coupon_infos()}
        return coupon_info.get(COUPON_TYPES.DOCTOR, {}).get('doctor_coupon_deduction', 0)

    def getval_activity_name(self, obj):
        try:
            activity_name = Special.objects.get(id=obj.activity_id).title
        except:
            activity_name = ''
        return activity_name

    def getval_discount_rate(self, obj):
        return '{}%'.format(int(obj.discount * 100.0/obj.service_price))

    def getval_real_discount(self, obj):
        if obj.operation_location_type == OPERATION_LOCATION_TYPE.WHITE_LIST:
            discount_rate = int(obj.discount * 100.0 / obj.service_price)
            real_discount = int((obj.service_price - obj.servicesnapshot.cost_price) * discount_rate * 0.01)
        else:
            real_discount = obj.discount
        return real_discount

def real_partner(doctor, end_time):
    if doctor is None or end_time is None:
        return ''
    now_partner = doctor.business_partener
    change_record = doctor.docbusinessrecord_set.filter(action_time__lte=end_time).last()
    return change_record.to_business if change_record else now_partner


@DB
class OrderDQ(DataSQLQuery):
    data_model = OrderDB
    model = Order

    def filter_check_groups(self, srch_key, srch_val, regex=False):
        _in, businessman_list, groups = get_business_team(ctx=None, user_id=srch_val)
        if _in:
            return Q(servicesnapshot__doctor__business_partener__in=businessman_list) | Q(servicesnapshot__doctor__business_group__in=groups)
        else:
            return Q()

    def filter_can_create_budan(self, srch_key, srch_val, regex=False):
        return Q(budan__isnull=True) | Q(budan__status=BUDAN_STATUS.CANCEL)

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

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

    def filter_service__doctor__name(self, srch_key, srch_val, regex=False):
        if srch_val:
            doctor_ids = Doctor.objects.filter(name__contains=srch_val).values_list('id', flat=True)
            service_ids = Service.objects.filter(doctor_id__in=doctor_ids).values_list('id', flat=True)
            return Q(service_id__in=list(service_ids))
        return Q()

    def filter_service__name(self, srch_key, srch_val, regex=False):
        if srch_val:
            service_ids = Service.objects.filter(name__contains=srch_val).values_list('id', flat=True)
            return Q(service_id__in=list(service_ids))
        return Q()

    def filter_address(self, srch_key, srch_val, regex=False):
        return Q(address__contains=srch_val)

    def filter_user_name(self, srch_key, srch_val, regex=False):
        if srch_val:
            user_ids = User.objects.filter(last_name__contains=srch_val).values_list('id', flat=True)
            return Q(user_id__in=list(user_ids))
        return Q()

    def filter_phone(self, srch_key, srch_val, regex=False):
        return Q(phone_crypt=srch_val)

    def filter_payment_channel(self, srch_key, srch_val, regex=False):
        return Q(payment_channel=srch_val)

    def filter_refund_comment(self, srch_key, srch_val, regex=False):
        q = Q()
        if srch_val:
            if isinstance(srch_val, list):
                for reason in srch_val:
                    q |= Q(refund_comment__contains=reason)
            else:
                q |= Q(refund_comment__contains=srch_val)
        return q

    def filter_activity_type(self, srch_key, srch_val, regex=False):
        if srch_val == '1':
            return Q(activity_type=2)
        if srch_val == '0':
            return ~Q(activity_type=2)
        return Q()

    def filter_out_trade_id(self, srch_key, srch_val, regex=False):
        q = Q()
        if srch_val:
            if isinstance(srch_val, list):
                for v in srch_val:
                    q |= Q(settlementitem__settlement__id=v[:12])
            else:
                q = Q(settlementitem__settlement__id=srch_val[:12])
        return q

    def order_settle_price(self, qs, field):
        qs = qs.annotate(settleprice=F(u'servicesnapshot__pre_payment_price') - F(
            u'discount') - F(u'servicesnapshot__coupon_doctor_value'))
        return qs, u'settleprice'

    def filter_high_com_service(self, key, value, regex=False):
        q = Q(service__service_type=SERVICE_SELL_TYPE.FENGXIANGGOU)
        if not int(value):
            q = ~q
        return q

    def filter_base_service_type(self, key, value, regex=False):
        if value:
            service_ids = Service.objects.filter(service_type__in=value)
            return Q(service_id__in=list(service_ids))
        return Q()

    def filter_service__doctor__hospital__name(self, srch_key, srch_val, regex=True):
        if srch_val:
            doctor_ids = Hospital.objects.filter(name__contains=srch_val).values_list('doctor_hospital__id', flat=True)
            service_ids = Service.objects.filter(doctor__in=doctor_ids).values_list('id', flat=True)
            return Q(service__in=list(service_ids))
        return Q()

    def filter_is_organization(self, srch_key, srch_val, regex=True):
        return Q(user__doctor__isnull=not bool(int(srch_val)), user__doctor__hospital__isnull=not bool(int(srch_val)))

    def filter_refund__refunded_at(self, srch_key, srch_val, regex=True):
        return self._qry_time_range(srch_key, srch_val, regex)

    def filter_call_time(self, srch_key, srch_val, regex=False):
        start, end = srch_val
        ids = ProtectPhone.objects.filter(bind_time__gte=start, bind_time__lte=end, event_type=USERCALL_EVENT_TYPE.ORDER_CHECK).values_list('event_id', flat=True)
        return Q(id__in=list(ids))
