# coding=utf8
from __future__ import unicode_literals, absolute_import, print_function

from datetime import date
from datetime import datetime

from django.db import models
from django.db.models import DateTimeField, BooleanField, CharField, IntegerField, FloatField, TextField
from django.db.models import ForeignKey, Q

from gm_types.gaia import PUNISHMENT_STATUS, PUNISHMENT_TARGET, PUNISHMENT_PV_LIMIT_DEMESION, PUNISHMENT_RANGE
from gm_types.gaia import PUNISHMENT_TYPE_FULL as PUNISHMENT_TYPE

from .doctor import Doctor
from .user import User
from .types import TICKETS_STATUS

end_of_today = lambda: date.today().strftime('%Y-%m-%d 23:59:59')


class TicketsResult(models.Model):
    """
    处罚结果
    """
    class Meta:
        app_label = 'api'

    doctor = models.OneToOneField(Doctor, related_name='ticketsresult')
    start_sink = models.DateTimeField(verbose_name=u'下沉开始时间', blank=True, null=True)
    end_sink = models.DateTimeField(verbose_name=u'下沉结束时间', blank=True, null=True)
    sink_days = models.IntegerField(verbose_name=u'下沉天数', blank=True, null=True)


class Tickets(models.Model):
    """
    罚单
    """

    class Meta:
        app_label = 'api'

    doctor = models.ForeignKey(Doctor)
    tickets_time = models.DateTimeField(verbose_name=u'开罚单时间')
    status = models.CharField(verbose_name=u'罚单状态', max_length=8, choices=TICKETS_STATUS,
                              default=TICKETS_STATUS.DEFAULT)
    is_valid = models.BooleanField(verbose_name='是否有效', default=True)
    tickets_result = models.ForeignKey(TicketsResult, verbose_name=u'处罚结果', blank=True, null=True)

    @property
    def sink_services(self):
        # 下沉美购
        sink_services = []
        singlerecords = self.singlerecord.filter(is_revoke=False)
        for singlerecord in singlerecords:
            if singlerecord.service is None:
                service_list = list(singlerecord.doctor.services.all())
                sink_services += service_list
            else:
                sink_services.append(singlerecord.service)
        return list(set(sink_services))

    def change_valid(self):
        if self.singlerecord.filter(is_revoke=False).exists():
            self.is_valid = True
        else:
            self.status = TICKETS_STATUS.DEFAULT
            self.tickets_result = None
            self.is_valid = False
        self.save()

    @property
    def single_num(self):
        return self.singlerecord.filter(is_revoke=False).count()


class TicketsresultRecord(models.Model):
    """
    处罚结果记录
    """
    class Meta:
        app_label = 'api'

    tickets_result = models.ForeignKey(TicketsResult)
    start_sink = models.DateTimeField(verbose_name=u'下沉开始时间', null=True, blank=True)
    end_sink = models.DateTimeField(verbose_name=u'下沉结束时间', null=True, blank=True)


class TicketsResultDetail(models.Model):

    class Meta:
        app_label = 'api'

    tickets_result = models.ForeignKey(TicketsResult)
    start_sink = models.DateTimeField(verbose_name=u'下沉开始时间', null=True, blank=True)
    end_sink = models.DateTimeField(verbose_name=u'下沉结束时间', null=True, blank=True)
    sink_days = models.IntegerField(verbose_name=u'下沉天数', null=True, blank=True)
    tickets_list = models.TextField(verbose_name=u'关联罚单')
    service_list = models.TextField(verbose_name=u'下沉美购')
    user = models.ForeignKey(User)
    created_time = models.DateTimeField(verbose_name=u'创建时间', auto_now=True)


class Punishment(models.Model):
    class Meta:
        verbose_name = '罚单V1'

    doctor = ForeignKey(Doctor)
    reason = CharField('处罚原因', max_length=32)
    start_time = DateTimeField('下沉开始时间')
    end_time = DateTimeField('下沉结束时间')
    comment = CharField('备注', max_length=256)
    enable = BooleanField(default=True)
    create_time = DateTimeField(auto_now_add=True)
    punish_type = IntegerField('处罚方式', choices=PUNISHMENT_TYPE, default=PUNISHMENT_TYPE.LIMIT)
    factor = FloatField('调权指数', default=1)
    target = CharField(u'下沉实体', max_length=20, choices=PUNISHMENT_TARGET, default=PUNISHMENT_TARGET.ALL)
    pv_limit = IntegerField('pv限制', default=0)
    range = IntegerField('处罚范围', choices=PUNISHMENT_RANGE, default=PUNISHMENT_RANGE.ALL)
    target_ids = CharField('部分处罚对象ids', max_length=1000, default='')

    @classmethod
    def get_time_list_by_doctor_id(cls, doctor_id):
        from hippo.views.doctor import get_merchant_doctor_id
        merchant = get_merchant_doctor_id.func({}, doctor_id)
        if merchant:
            doctor_id = merchant['merchant_doctor_id']
            punish = cls.objects.filter(doctor_id=doctor_id, punish_type=PUNISHMENT_TYPE.LIMIT, enable=True, end_time__gt=datetime.now())
            return [[x.start_time, x.end_time] for x in punish]
        return []

    @classmethod
    def get_factor_list_by_doctor_id(cls, doctor_id):
        from hippo.views.doctor import get_merchant_doctor_id
        merchant = get_merchant_doctor_id.func({}, doctor_id)
        if merchant:
            doctor_id = merchant['merchant_doctor_id']
            f = Q(doctor_id=doctor_id, enable=True, end_time__gt=datetime.now())
            punish = cls.objects.filter(f).order_by('-create_time')
            PT = PUNISHMENT_TYPE
            TWeight = {PT.LIMIT: 1, PT.WEIGHT: 3, PT.ADVERTISE: 2}
            punish = sorted(punish, key=lambda x: TWeight[x.punish_type])
            return [[x.start_time, x.end_time, x.factor, x.punish_type] for x in punish]
        return []

    @classmethod
    def get_punishment_by_doctor_id(cls, doctor_id):
        from hippo.views.doctor import get_merchant_doctor_id
        merchant = get_merchant_doctor_id.func({}, doctor_id)
        result = {'diary': {}, 'service': {}, 'doctor': {}, 'qa': {}}
        if merchant:
            doctor_id = merchant['merchant_doctor_id']
            f = Q(doctor_id=doctor_id, enable=True, end_time__gt=datetime.now())
            punish = cls.objects.filter(f).order_by('-create_time')
            PT = PUNISHMENT_TYPE
            TWeight = {PT.LIMIT: 3, PT.WEIGHT: 2, PT.ADVERTISE: 4, PT.PV: 1}
            punishs = sorted(punish, key=lambda x: TWeight[x.punish_type])
            result = reduce(cls.override, [x.data() for x in punishs], result)
        return result

    @classmethod
    def get_punishment_by_doctor_id_v2(cls, doctor_id):
        from hippo.views.doctor import get_merchant_doctor_id
        merchant = get_merchant_doctor_id.func({}, doctor_id)
        result = {'diary': {}, 'service': {}, 'doctor': {}, 'qa': {}}
        if merchant:
            doctor_id = merchant['merchant_doctor_id']
            f = Q(doctor_id=doctor_id, enable=True, end_time__gt=datetime.now(), start_time__lt=datetime.now())
            punish = cls.objects.filter(f).order_by('-create_time')
            PT = PUNISHMENT_TYPE
            TWeight = {PT.LIMIT: 3, PT.WEIGHT: 2, PT.ADVERTISE: 4, PT.PV: 1}
            punishs = sorted(punish, key=lambda x: TWeight[x.punish_type])
            result = reduce(cls.override, [x.data() for x in punishs], result)
        return result

    @classmethod
    def get_punishment_service(cls):
        from hippo.models import Merchant
        from hippo.models import MerchantRelevance
        from .. import Service
        f = Q(enable=True, end_time__gt=datetime.now(), start_time__lt=datetime.now(), punish_type=1)
        punishs = cls.objects.filter(f)
        result = {}
        for punish in punishs:
            k = punish.factor
            if punish.range == 1:
                merchant_doctor_id = punish.doctor
                merchant = Merchant.objects.get(doctor_id=merchant_doctor_id)
                doctor_ids = MerchantRelevance.objects.filter(merchant_id=merchant.id).values_list('doctor_id')
                service_ids = Service.objects.filter(doctor_id__in=doctor_ids).values_list('id')
                for service_id in service_ids:
                    result[int(service_id[0])] = k
            else:
                service_ids = str(punish.target_ids).split(',')
                for service_id in service_ids:
                    result[int(service_id)] = k

        return result

    @property
    def status(self):
        if not self.enable:
            return PUNISHMENT_STATUS.CANCEL
        now = datetime.now()
        if now < self.start_time:
            return PUNISHMENT_STATUS.PRE
        elif now < self.end_time:
            return PUNISHMENT_STATUS.ING
        else:
            return PUNISHMENT_STATUS.DONE

    @staticmethod
    def override(base, more):
        for key in filter(lambda x: more[x], more):
            base[key] = more[key]
        return base

    def data(self):
        result = {'diary': {}, 'service': {}, 'doctor': {}, 'qa': {}}
        if self.status in [PUNISHMENT_STATUS.CANCEL, PUNISHMENT_STATUS.DONE]:
            return result
        if self.punish_type == PUNISHMENT_TYPE.PV:
            if not self.records.filter(end_time=end_of_today()).exists():
                return result
        data = {
            'start_time': self.start_time,
            'end_time': self.end_time,
            'factor': self.factor,
            'range': self.range,
            'target_ids': self.target_ids,
            'type': 'limit'
        }
        if self.punish_type == PUNISHMENT_TYPE.LIMIT:
            if self.target == PUNISHMENT_TARGET.ALL:
                [result.update(**{key: data}) for key in result]
            else:
                result[self.target] = data
        elif self.punish_type == PUNISHMENT_TYPE.WEIGHT:
            data['type'] = 'weight'
            result['diary'] = data
        elif self.punish_type == PUNISHMENT_TYPE.ADVERTISE:
            [result.update(**{key: data}) for key in result]
        elif self.punish_type == PUNISHMENT_TYPE.PV:
            record = self.records.get(end_time=end_of_today())
            data['start_time'] = record.start_time
            data['end_time'] = record.end_time
            if self.target == PUNISHMENT_PV_LIMIT_DEMESION.SERVICE:
                result['service'] = data
            elif self.target == PUNISHMENT_PV_LIMIT_DEMESION.DIARY:
                result['diary'] = data
        return result


class PvPunishmentRecord(models.Model):
    class Meta:
        verbose_name = 'pv 罚单记录'

    punishment = ForeignKey(Punishment, related_name='records')
    start_time = DateTimeField(auto_now_add=True)
    end_time = DateTimeField(default=end_of_today)
    pv_limit = IntegerField(default=0)
