# coding:utf-8

from __future__ import unicode_literals

import dateutil.parser as parser
import time
import datetime

from api.models import Merchant, Coupon, GiftToCoupon

from django.core.management import BaseCommand
from rpc.tool.error_code import CODES

from search.utils.conversation import search_conversation_from_es
from services.unread.stat import UserUnread

from api.models.types import MESSAGE_TYPE
from hippo.models import MerchantRelevance, Doctor
from gm_types.gaia import DOCTOR_TYPE, COUPON_TYPES, COUPON_DISTRIBUTION_STATUS
from gm_types.msg import CONVERSATION_ORDER, CONVERSATION_TYPE
from gm_types.trade import COUPON_TIME_TYPE
from message.views.message import internal_message_send
from api.models.message import ConversationUserStatus

from rpc.exceptions import RPCPermanentError


def get_conversations_v3(user_ids, offset, size, order_by=CONVERSATION_ORDER.LAST_REPLY_TIME,
                         last_reply_time_start=None, last_reply_time_end=None, reply_status=None,
                         is_star=None, user_id=None, user_last_name=None, comment=None):
    """
    获取会话列表， 与v2不同的是全部走es获取conversation_ids
    :param user_ids: LIST[USER_ID]
    :param offset: INT 偏移量
    :param size: INT 每页数量
    :param order_by: 排序规则
    :param last_reply_time_start: str 最后回复开始时间筛选
    :param last_reply_time_end: str 最后回复结束时间筛选
    :param reply_status: bool 回复状态（新消息、旧消息）
    :param is_star: bool
    :param user_id: int 精确搜索用户ID
    :param user_last_name: int 搜索用户昵称
    :param comment: int 搜索备注
    :return:
    """
    if not isinstance(user_ids, list):
        raise RPCPermanentError
    if not isinstance(size, int):
        raise RPCPermanentError
    if size <= 0 or size >= 50:
        size = 50
    es_filters = {'user_ids': user_ids}
    if is_star is not None and isinstance(is_star, bool):
        es_filters['is_star'] = is_star
    if last_reply_time_start is not None:
        es_filters['last_reply_time_start_gte'] = parser.parse('{}+0800'.format(last_reply_time_start)).isoformat()
    if last_reply_time_end is not None:
        es_filters['last_reply_time_end_lte'] = parser.parse('{}+0800'.format(last_reply_time_end)).isoformat()
    es_query = dict()
    # if search_content is not None:
    #     es_query = {
    #         'comment': search_content,
    #         'user_last_name': search_content,
    #     }
    if user_id is not None:
        es_query['user_id'] = user_id
    if user_last_name:
        es_query['user_last_name'] = user_last_name
    if comment:
        es_query['comment'] = comment
    es_sort_type = order_by
    # 全部
    es_result_total = search_conversation_from_es(offset=offset, size=size, filters=es_filters,
                                                  query=es_query, sort_type=es_sort_type)
    # 已回复
    es_filters['multi_filter_status'] = {
        'status': True,
        'user_ids': user_ids,
    }
    es_result_reply = search_conversation_from_es(offset=offset, size=size, filters=es_filters,
                                                  query=es_query, sort_type=es_sort_type)
    # 未回复
    es_filters['multi_filter_status'] = {
        'status': False,
        'user_ids': user_ids,
    }
    es_result_not_reply = search_conversation_from_es(offset=offset, size=size, filters=es_filters,
                                                      query=es_query, sort_type=es_sort_type)
    # es_result = search_conversation_from_es(offset=offset, size=size, filters=es_filters,
    #                                         query=es_query, sort_type=es_sort_type)
    if reply_status == None:
        es_result = es_result_total
    else:
        if reply_status:
            es_result = es_result_reply
        else:
            es_result = es_result_not_reply
    _conversation_ids = es_result['conversation_ids']
    cus_ids = []
    for conversation_id in _conversation_ids:
        sub_ids = ConversationUserStatus.objects.filter(
            user_id__in=user_ids, conversation_id=conversation_id
        ).values_list('id', flat=True)
        cus_ids.extend(list(sub_ids))
    conversation_user_status = ConversationUserStatus.objects.filter(id__in=cus_ids).order_by('-last_reply_time')

    conversation_info_list = [cs.conversation.conversation_info_v3(cs, user_ids) for cs in conversation_user_status]
    conversation_id_to_user_id = {cs.conversation_id: cs.user_id for cs in conversation_user_status}
    for c in conversation_info_list:
        default = 1 if c['is_new'] else 0
        c['unread_num'] = UserUnread(conversation_id_to_user_id[c['id']]
                                     ).get_conversation_unread(c['id'], default=default)
    return {
        'conversation_list': conversation_info_list,
        'total_count': es_result_total['total_count'],
        'reply_total': es_result_reply['total_count'],
        'not_reply_total': es_result_not_reply['total_count']
    }


class Command(BaseCommand):
    DOCTOR_BUSINESS_CHANNAL_ID_ONLINE = 35

    # only check merchant id can use
    availableMerchantIDList = []

    # check merchant id and coupon can use
    availableMerchantIDListWithCoupon = []

    onlineTestuid = 33703995

    # content = [["area", "merchant_name", 6477328345687146383, 533, 0, "福建最大的整形机构在线独家补贴，领取红包为美减压，爱美就到爱美尔"]]

    c = [
        ["华东", "上海仁爱医院", 6329570401814877850, 61232, 0, "浪漫“七夕” 遇见更美的你  直播全场嗨翻不限购 177元---【除皱单部位足量一次】677元---【瘦脸足量一次】677元---伊婉C  1ml【另送面膜1盒，每人限一次】5970元---眼部四项5970元---中下面部提升【童颜线】5970元---网红小翘鼻15110元----荣誉主任亲诊颧骨内推+颧弓缩窄手术术式一口价 【送钛板钛钉】16800元---【荣誉主任亲诊基础下颌角术式一口价】直播秒杀福利奖：满5000元奖   TF口红真品可验满10000元奖  香奈儿香水                               满20000元奖  迪斯尼双人门票满30000元奖  戴森吹风机满50000元奖  佘山深坑洲际酒店1晚 或  华为P40pro(128G)直播间签到礼品牌巧克力1盒或USB小风扇1个（二选一）回复你想了解的项目，让我优先为您详细解答哦~"],
        ["华东", "蛋白医疗美容连锁（淮海路店）", 6328834655336319173, 61231, 0,
         "心意解码 惠满七夕#蛋白七夕专场直播秒杀#今晚19:00—21:0077元皮秒/777元超皮秒——限时秒杀【还有香奈儿LV等大牌六重豪礼等你来拿】想你所想，给你想要让美与你共赴甜蜜抄底狂欢夜 与你不见不散"],
        ]

    def handle(self, *args, **options):
        self.checkMerchant()
        self.checkCoupon()

        self.sendCoupon()

    def sendCoupon(self):

        resMerchantFailedSend = {}
        resMerchantSucceedSend = {}
        resConversationMap = {}

        sendReqNum = 0
        timeStart = time.time()

        for line in self.availableMerchantIDListWithCoupon:

            failedSendUserList = []
            succeedSendUserList = []
            allConversationID = []

            doctorIDList = []
            doctorUIDList = []
            sendCouponAdminUID = 0
            targetUserSet = set()
            sendCouponList = []
            conversationList = []

            merchantID = line[2]

            print()
            print()
            print("start send coupon of merchant id: {merchantID}".format(merchantID=merchantID))
            print("merchant id: ", merchantID)
            couponID1 = line[3]
            print("coupon id 1: ", couponID1)
            couponID2 = line[4]
            print("coupon id 2: ", couponID2)
            sendCouponList.append(couponID1)
            sendCouponList.append(couponID2)

            sendGiftList = self.getGiftID(sendCouponList)
            print "gift list: "
            print sendGiftList
            msgContent = line[5]
            print("msg content: ", msgContent)

            # get merchant info
            merchant = Merchant.objects.filter(id=merchantID).first()
            if not merchant:
                continue

            # get admin doctor id
            adminDoctorID = merchant.doctor.id

            # add admin doctor id to doctorIDList
            doctorIDList.append(adminDoctorID)

            # get other doctors
            doctors = MerchantRelevance.objects.filter(merchant_id=merchantID, doctor__doctor_type=DOCTOR_TYPE.DOCTOR)
            doctorCount = doctors.count()
            ds = doctors[0: doctorCount]
            otherDoctorList = [d.doctor.id for d in ds]

            # add other doctor id to doctorIDList
            doctorIDList.extend(otherDoctorList)

            # get all doctor info
            doctors = Doctor.objects.filter(pk__in=doctorIDList)

            for doctor in doctors:

                ddid = doctor.id
                duid = doctor.user_id

                # add every doctor uid to doctorUIDList
                doctorUIDList.append(duid)
                if ddid == adminDoctorID:
                    sendCouponAdminUID = duid

            # get message target user' user_id list at 2020/4/1 - 2020/7/31
            offsetNumber = 0
            while True:

                # get conversations between 2020/4/1 -- 2020/6/30 of merchant
                conversationResList = get_conversations_v3(
                    user_ids=doctorUIDList,
                    offset=offsetNumber,
                    size=50,
                    is_star=0,
                    last_reply_time_start="2020-01-01T00:00:00",
                    last_reply_time_end="2020-08-23T00:00:00",
                )

                # print("msg res: ")
                # pprint.pprint(conversationResList)
                resCount = conversationResList["total_count"]

                # no conversation
                if resCount <= 0:
                    break

                conversationListOne = conversationResList["conversation_list"]

                conversationList.extend(conversationListOne)

                if len(conversationListOne) < 50:
                    break

                offsetNumber += 50

            conversationNum = len(conversationList)
            print("conversation number of merchant: {merchantID} in 2020-1-1 and 2020-8-23 is ".format(
                merchantID=merchantID), conversationNum)

            # no conversation, handle next merchant
            if conversationNum == 0:
                continue

            # get target user id set
            # 因为发送者和接收者，顺序不定，所以都取出来去判断
            for conversationRow in conversationList:

                targetUserID0 = conversationRow["user_ids"][0]
                targetUserID1 = conversationRow["user_ids"][1]
                conversationID = conversationRow["id"]

                allConversationID.append(conversationID)

                if targetUserID0 not in doctorUIDList:
                    targetUserSet.add(targetUserID0)

                if targetUserID1 not in doctorUIDList:
                    targetUserSet.add(targetUserID1)

            # print("target user id set: ", targetUserSet)
            targetUserNum = len(targetUserSet)
            print("target user number of merchant id:{merchantID} is ".format(merchantID=merchantID), targetUserNum)

            targetUserSet.add(self.onlineTestuid)

            for targetUserOne in targetUserSet:

                for giftID in sendGiftList:

                    resSendCoupon = internal_message_send(
                        sender_user_id=sendCouponAdminUID,
                        target_user_id=targetUserOne,
                        msg_type=MESSAGE_TYPE.GIFT,
                        conversation_type=CONVERSATION_TYPE.MESSAGE,
                        content={"gift_id": giftID, "channel_id": self.DOCTOR_BUSINESS_CHANNAL_ID_ONLINE}
                    )

                    sendReqNum += 1

                    errSendGift = resSendCoupon["error"]
                    # send failed
                    if errSendGift == CODES.MESSAGE_CONTENT_FILTERED_OUT:
                        # print(
                        #     "Failed to send merchant:{merchantID}'s coupon: {couponGiftID} to user: {targetIDOne}".format(
                        #         merchantID=merchantID, couponGiftID=giftID, targetIDOne=targetUserOne))

                        failedGiftInfo = str(giftID) + "_" + str(targetUserOne)
                        failedSendUserList.append(failedGiftInfo)

                    # send success
                    # if errSendGift == CODES.SUCCESS:
                    #     print(
                    #         "Succeed to send merchant:{merchantID}'s coupon: {couponGiftID} to user: {targetIDOne}".format(
                    #             merchantID=merchantID, couponGiftID=giftID, targetIDOne=targetUserOne))

                # send msg
                resSendMsg = internal_message_send(
                    sender_user_id=sendCouponAdminUID,
                    target_user_id=targetUserOne,
                    msg_type=MESSAGE_TYPE.TEXT,
                    conversation_type=CONVERSATION_TYPE.MESSAGE,
                    content={"text": msgContent}
                )

                sendReqNum += 1

                errSendMsg = resSendMsg["error"]
                # if errSendMsg == CODES.MESSAGE_CONTENT_FILTERED_OUT:
                #     print(
                #         "Failed to send merchant:{merchantID}'s msg to user: {targetIDOne}".format(
                #             merchantID=merchantID, targetIDOne=targetUserOne))

                if errSendMsg == CODES.SUCCESS:
                    # print(
                    #     "Succeed to send merchant:{merchantID}'s msg to user: {targetIDOne}".format(
                    #         merchantID=merchantID, targetIDOne=targetUserOne))
                    succeedSendUserList.append(targetUserOne)

            resMerchantFailedSend[merchantID] = failedSendUserList
            resConversationMap[merchantID] = allConversationID
            resMerchantSucceedSend[merchantID] = succeedSendUserList

            print("send coupon complete of merchant: {merchantID}".format(merchantID=merchantID))

        print("res failed to send: ")
        print(resMerchantFailedSend)

        print("res succeed to send: ")
        print(resMerchantSucceedSend)

        print("conversation id list: ")
        print(resConversationMap)

        print("total send request number: ", sendReqNum)

        timeEnd = time.time()
        timeUse = timeEnd - timeStart
        print("time use: ", timeUse)

    def checkMerchant(self):

        unavailableMerchantList = []

        print "===== start to check merchant id ====="

        for line in self.c:
            merchantID = line[2]

            m = Merchant.objects.filter(id=merchantID).first()
            if not m:
                unavailableMerchantList.append(line)
            else:
                self.availableMerchantIDList.append(line)

        print "=== result of check merchant id ==="
        print "num of unavailable line with merchant:"
        print len(unavailableMerchantList)
        print "content of unavailable line with merchant:"
        print unavailableMerchantList
        print "===== end to check merchant id ====="

    def checkCoupon(self):

        unavailableMerchantInfoSet = set()

        print "===== start to check coupon id ====="

        for line in self.availableMerchantIDList:

            doctorIDList = []
            couponList = []

            merchantID = line[2]
            couponID1 = line[3]
            couponID2 = line[4]
            couponList.append(couponID1)
            couponList.append(couponID2)

            # get merchant obj
            m = Merchant.objects.filter(id=merchantID).first()

            # get admin doctor
            adminDoctorID = m.doctor.id
            print "admin doctor", adminDoctorID

            # add admin doctor id to doctorIDList
            doctorIDList.append(adminDoctorID)

            # get other doctors
            doctors = MerchantRelevance.objects.filter(merchant_id=merchantID, doctor__doctor_type=DOCTOR_TYPE.DOCTOR)
            doctorCount = doctors.count()
            ds = doctors[0: doctorCount]
            otherDoctorList = [d.doctor.id for d in ds]

            doctorIDList.extend(otherDoctorList)
            print "doctor list: ", doctorIDList

            # get doctor of every coupon, find it is exist in doctor list
            for couponID in couponList:
                if couponID == 0:
                    continue

                c = Coupon.objects.filter(id=couponID).first()
                if not c:
                    unavailableMerchantInfoSet.add(merchantID)
                    continue

                createDoctor = c.doctor
                if not createDoctor:
                    unavailableMerchantInfoSet.add(merchantID)
                    continue

                createDoctorID = createDoctor.id

                # coupon's create doctor is not belong to merchant,
                # add to unavailableMerchantInfoSet
                if createDoctorID not in doctorIDList:
                    unavailableMerchantInfoSet.add(merchantID)
                    continue

                couponType = c.coupon_type

                # coupon's type is not COUPON_TYPES.DOCTOR,
                # add to unavailableMerchantInfoSet
                if couponType != COUPON_TYPES.DOCTOR:
                    unavailableMerchantInfoSet.add(merchantID)
                    continue

                distributionStatus = c.distribution_status

                # coupon's distribution status is not COUPON_DISTRIBUTION_STATUS.OPEN,
                # add to unavailableMerchantInfoSet
                if distributionStatus != COUPON_DISTRIBUTION_STATUS.OPEN:
                    unavailableMerchantInfoSet.add(merchantID)
                    continue

                timeType = c.time_type

                # if time type is COUPON_TIME_TYPE.START_END,
                # check start_time <= now <= end_time,
                # if incompatible, add to unavailableMerchantInfoSet
                if timeType == COUPON_TIME_TYPE.START_END:
                    startDataTime = c.start_time
                    endDataTime = c.end_time

                    nowTime = datetime.datetime.now()

                    if nowTime < startDataTime or nowTime > endDataTime:
                        unavailableMerchantInfoSet.add(merchantID)
                        continue

                # if can't find GiftToCoupon obj where coupon.id=couponID,
                # add to unavailableMerchantInfoSet
                couponGift = GiftToCoupon.objects.filter(coupon_id=couponID).first()
                if not couponGift:
                    unavailableMerchantInfoSet.add(merchantID)
                    continue

                # if coupon is not enable, add to unavailableMerchantInfoSet
                isEnable = couponGift.coupon_enable
                if not isEnable:
                    unavailableMerchantInfoSet.add(merchantID)
                    continue

        print "===== result of check coupon id ====="
        print "num of unavailable line with merchant and coupon:"
        print len(unavailableMerchantInfoSet)
        print "content of unavailable line with merchant and coupon:"
        print unavailableMerchantInfoSet
        print "===== end to check coupon id ====="

        for line in self.c:

            mid = line[2]

            if mid in unavailableMerchantInfoSet:
                continue

            self.availableMerchantIDListWithCoupon.append(line)

        print "===== available line with merchant and coupon ====="
        print self.availableMerchantIDListWithCoupon
        print "================ END ======================"

    @staticmethod
    def getGiftID(couponList):

        giftList = []

        for couponID in couponList:
            if couponID == 0:
                continue

            couponGift = GiftToCoupon.objects.filter(coupon_id=couponID).first()
            giftID = couponGift.coupon_gift.id
            giftList.append(giftID)

        return giftList
