# -*- coding: utf8 -*-
from __future__ import unicode_literals, absolute_import, print_function
import json
import hashlib
from django.db import models
from django.conf import settings
from api.models import Person, Order, CouponInfo, ORDER_STATUS, RM_STATUS, \
    PeriodHospital, OrderCouponInfo
from gm_types.trade import SETTLEMENT_PAY_MODE

# Enumeration is deprecated, reference: http://git.gengmei.cc/backend/gm-types
#from rpc.tool.enumeration import Enumeration
from gm_types.gaia import USE_COUPON_TYPE, SERVICE_PAYMENT_TYPE, SETTLEMENT_STATUS, SETTLEMENT_CANCEL_REASON
from gm_types.gaia import SETTLEMENT_TYPE

SETTLEMENT_ID_LEN = 12


class Settlement(models.Model):
    class Meta:
        verbose_name = u'结算单信息'
        verbose_name_plural = u'结算单信息'
        db_table = 'api_settlement'
        app_label = 'api'

    orders = models.ManyToManyField(Order, through='SettlementItem', related_name='settlement')
    id = models.CharField(max_length=12, verbose_name=u'结算单号', primary_key=True)
    name = models.CharField(max_length=255, verbose_name=u'结算单名称', default='')
    person = models.ForeignKey(Person, verbose_name=u'用户')
    payment = models.FloatField(verbose_name=u'支付额', default=0)
    points_deduction = models.FloatField(verbose_name=u'美分抵扣', default=0)
    coupon_deduction = models.FloatField(verbose_name=u'美劵抵扣', default=0)
    created_at = models.DateTimeField(auto_now_add=True, verbose_name=u"创建时间")
    expired_at = models.DateTimeField(auto_now_add=True, verbose_name=u"过期时间")
    coupon = models.ForeignKey(CouponInfo, null=True, blank=True, default=None)
    real_payment = models.FloatField(verbose_name=u'实际付款额', default=0)
    form_id = models.CharField(verbose_name=u'推送消息form_id, 有效期7天', max_length=256,default="")
    coupon_info_ids_data = models.CharField(max_length=1024, verbose_name=u'JSON格式的coupon_info_ids')

    service_payment_type = models.CharField(
        verbose_name=u'美购付款模式', max_length=1,
        choices=SERVICE_PAYMENT_TYPE,
        default=SERVICE_PAYMENT_TYPE.FULL_PAYMENT
    )

    status = models.CharField(
        max_length=1, choices=SETTLEMENT_STATUS, default=SETTLEMENT_STATUS.NOT_PAID,
        null=False, verbose_name=u'付款状态'
    )

    cancel_reason = models.IntegerField(verbose_name=u'取消原因', choices=SETTLEMENT_CANCEL_REASON,
                                        default=SETTLEMENT_CANCEL_REASON.UNKNOWN)

    # TODO: 待删除
    use_coupon_type = models.CharField(
    max_length=1, choices=USE_COUPON_TYPE,
    default=USE_COUPON_TYPE.NOT_USE, null=False,
    verbose_name=u'整单使用，还是只用在了单个美购'
    )



    # 新增
    # !!! 注意
    # 只有status 为支付完成时, pay_mode 才具有准确性
    pay_mode = models.IntegerField(choices=SETTLEMENT_PAY_MODE, verbose_name='微信支付宝applepay 分期', default=SETTLEMENT_PAY_MODE.COMMON)
    service_price = models.FloatField(verbose_name=u'订单总价', default=0)
    # 删去
    pay_callback_info = models.TextField(default='', verbose_name='支付回掉信息快照') # Deprecated in Apple PAY

    device_id = models.CharField(max_length=100, verbose_name=u'设备ID', db_index=True)
    # add in 7.7.25 自动创建日记本标识 注意：v 7.7.25 之后版本不再自动创建!!!
    auto_create_diary = models.BooleanField(verbose_name=u'该结算单下，订单支付成功后是否自动创建日记本', default=True)
    settlement_type = models.IntegerField(verbose_name=u'结算单类型', choices=SETTLEMENT_TYPE, default=SETTLEMENT_TYPE.NORMAL_ORDER)

    def get_coupon_info_ids(self):
        result = []
        if self.coupon_info_ids_data:
            result = json.loads(self.coupon_info_ids_data)
        elif self.coupon_id:
            result = [self.coupon_id]
        return result

    @property
    def coupon_info(self):
        return self.coupon

    def get_coupon_name(self):
        coupon_info_ids = self.get_coupon_info_ids()
        if len(coupon_info_ids) != 1:
            # 只有用一张券的时候才能正确显示券名称
            return u''
        coupon_info_id = coupon_info_ids[0]
        return CouponInfo.objects.get(id=coupon_info_id).coupon.name

    @property
    def is_installment(self):
        try:
            self.installment
            return True
        except:
            return False

    def get_renmai_status(self, ctx):
        try:
            renmai_list = ctx.rpc_remote['plutus/installment/installment/status'](
                settlement_list=[self.id]).unwrap()
            return renmai_list.status
        except:
            pass
        return RM_STATUS.NONE

    @property
    def is_support_renmai_no_pay(self):
        try:
            service = SettlementItem.objects.filter(settlement=self).first().order.service
            is_stage = service.is_stage
            if is_stage and self.service_payment_type == SERVICE_PAYMENT_TYPE.PREPAYMENT \
                    and self.status == SETTLEMENT_STATUS.NOT_PAID:
                price = self.hospital_payment
                if settings.RENMAI_INSTALLMENT_MIN_PAY <= price <= settings.RENMAI_INSTALLMENT_MAX_PAY:
                    return True
        except:
            pass
        return False

    @property
    def is_support_yirendai_no_pay(self):
        try:
            service = SettlementItem.objects.filter(settlement=self).first().order.service
            is_stage = service.is_stage
            if is_stage and self.service_payment_type == SERVICE_PAYMENT_TYPE.PREPAYMENT \
                    and self.status == SETTLEMENT_STATUS.NOT_PAID \
                    and self.items.count() == 1 \
                    and PeriodHospital.check_hospital_in_list(self.service.doctor.hospital):
                price = self.hospital_payment
                if settings.RENMAI_INSTALLMENT_MIN_PAY <= price <= settings.RENMAI_INSTALLMENT_MAX_PAY:
                    return True
        except:
            pass
        return False

    def is_support_renmai(self):
        try:
            if self.service_payment_type == SERVICE_PAYMENT_TYPE.PREPAYMENT \
                    and self.status == SETTLEMENT_STATUS.PAID\
                    and self.items.count() == 1:
                price = self.service_price - self.payment
                if settings.RENMAI_INSTALLMENT_MIN_PAY <= price <= settings.RENMAI_INSTALLMENT_MAX_PAY:
                    return True
        except:
            pass
        return False


class SettlementItem(models.Model):
    class Meta:
        verbose_name = u'结算单单项信息'
        db_table = 'api_settlementitem'
        app_label = 'api'

    settlement = models.ForeignKey(Settlement, related_name='items')
    order = models.OneToOneField(Order)
    #TODO: 将要去掉
    points_deduction = models.FloatField(verbose_name=u'美分抵扣', default=0)

    def get_actual_refund(self):
        used_coupon_info = self.settlement.coupon_info
        if not used_coupon_info:
            return self.order.payment
        from api.manager import order_manager
        if order_manager.can_refund_directly(self.order, used_coupon_info):
            return self.order.payment

        refundeds = self.settlement.items.filter(order__status=ORDER_STATUS.REFUNDED)
        has_refunded_ordinary = False
        refunded_count = 0

        for r in refundeds:
            if not order_manager.can_refund_directly(r.order, used_coupon_info):
                if not has_refunded_ordinary:
                    refunded_count += r.order.payment - self.settlement.coupon.value
                else:
                    refunded_count += r.order.payment
                has_refunded_ordinary = True
            else:
                refunded_count += r.order.payment

        # 防御性编程, 怕背锅
        # Defensive programming, scared of being a scapegoat
        if has_refunded_ordinary and (self.settlement.payment - refunded_count) >= self.order.payment:
            return self.order.payment

        if self.order.payment > self.settlement.coupon.value:
            return self.order.payment - self.settlement.coupon.value

        return 0
