#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__: vv
# Date: 2019/8/31
import tablib
from celery import shared_task
from datetime import datetime, timedelta
from hera.utils import get_mail_instance, attach_title
from api.models import BDTransfer, BDTransferOperationRecord, User, ItemWiki, BDTransferSingleRecord, TagWiki, BDTransferCommunicationRecord
from gm_types.gaia import OPERATION_ACTION, USER_POTENTIAL, BDTRANSFER_OBJECT_STATE, SINGLE_TYPE, TREATMENT_MEANS_CHOICES

DATETIME_FMT = '%Y-%m-%d'
OPERATION_USER_ID = 31618301
SUR_OPERATION_TYPE = True

to_mail_list = [
    "chenwei@igengmei.com",
    "zhaohuatian@igengmei.com",
    "lvguowei@igengmei.com",
    "zhaoyun@igengmei.com",
    "yangshuang@igengmei.com",
    "jianzirui@igengmei.com",
]

map_status = {
    BDTRANSFER_OBJECT_STATE.HAS_SENT_SINGLE: SINGLE_TYPE.NO_ORDER_FORM,
    BDTRANSFER_OBJECT_STATE.HAS_MADE_APPOINTMENT: SINGLE_TYPE.HAS_APPOINTMENT,
    BDTRANSFER_OBJECT_STATE.HAS_CONSULTATION: SINGLE_TYPE.HAS_CONSULTATION,
}


def send_export_mail(subject, body, to_list, send=True, attach_excel=False, dt=None):
    if not isinstance(to_list, (list, tuple)):
        to_list = [to_list]
    mail = get_mail_instance(subject, body, to_list)
    if attach_excel:
        mail.attach(attach_title(u'{}.xlsx'.format(subject)), dt.xlsx)
    if send:
        mail.send()
    return mail


def get_target_bdtransfer_tag_ids(bd_obj, status=SINGLE_TYPE.NO_ORDER_FORM):
    """
    获取线索下所有转诊补单关联的所有标签
    :param bd_obj:
    :param status: HAS_CONSULTATION or NO_ORDER_FORM
    :return:
    """
    tag_ids = []
    single_record_objs = bd_obj.single_records.filter(status=status)
    for dd in single_record_objs:
        tag_ids.extend(list(dd.project.filter(is_online=True).values_list('id', flat=True)))
    return set(tag_ids)


def get_target_bdtransfer_operation_type(bd_obj, status=SINGLE_TYPE.NO_ORDER_FORM):
    """
    根据tag_id获取线索手术性质
    :param bd_obj:
    :param status:
    :return:
    """
    tag_ids = get_target_bdtransfer_tag_ids(bd_obj, status=status)
    itemwiki_ids = TagWiki.objects.filter(tag_id__in=tag_ids).values_list("itemwiki_id", flat=True)
    if ItemWiki.objects.filter(id__in=itemwiki_ids, treatment_means=TREATMENT_MEANS_CHOICES.OPERATE).exists():
        return True
    else:
        return False


def get_target_bdtransfer_single_time(bd_obj, status=SINGLE_TYPE.NO_ORDER_FORM):
    """
    获取转诊补单状态变更时间
    :param bd_obj:
    :param status: HAS_CONSULTATION  or NO_ORDER_FORM
    :return:
    """
    the_first_single_record_obj = bd_obj.single_records.filter(status=status).first()
    if the_first_single_record_obj:
        return the_first_single_record_obj.single_time
    else:
        return None


def get_target_bdtransfer_consult_time(bd_obj, status=SINGLE_TYPE.HAS_CONSULTATION):
    the_first_single_record_obj = bd_obj.single_records.filter(status=status).first()
    if the_first_single_record_obj:
        return the_first_single_record_obj.consultation_time
    else:
        return None


def get_target_time(bd_obj, status):
    if status == SINGLE_TYPE.NO_ORDER_FORM or status == SINGLE_TYPE.HAS_APPOINTMENT:
        return get_target_bdtransfer_single_time(bd_obj, status=status)
    elif status == SINGLE_TYPE.HAS_CONSULTATION:
        return get_target_bdtransfer_consult_time(bd_obj, status=status)


def get_valid_time_window(single_time, span=30, chuck_size=3):
    now_time = datetime.now()
    delta = (now_time - single_time).days - span  # 时间差
    if delta >= 30:
        delta = 30  # 限制往后计数30天

    chunk = delta / 3  # 计算还剩下多少个时间窗口
    if delta <= 2 or chunk <= 0:
        return []

    # 获取零点时间
    single_time_zero = single_time - timedelta(
        hours=single_time.hour, minutes=single_time.minute,
        seconds=single_time.second, microseconds=single_time.microsecond)

    # now_time_zero = now_time - timedelta(
    #     hours=now_time.hour, minutes=now_time.minute,
    #     seconds=now_time.second, microseconds=now_time.microsecond)

    # 生成有效时间范围
    valid_datetime_range = []
    for chk in range(0, chunk):
        time_start, time_end = [
            single_time_zero + timedelta(days=span + (chk * chuck_size)),
            single_time_zero + timedelta(days=span + (chk + 1) * chuck_size)
        ]
        if now_time > time_end:
            valid_datetime_range.append((time_start, time_end))

    return valid_datetime_range


def get_valid_nums(bd_obj, datetime_range):
    count, success = 0, 0
    for time_range in datetime_range:
        is_valid = BDTransferCommunicationRecord.objects.filter(
            communication_time__range=time_range, bdtransfer=bd_obj).exists()
        # 窗口无沟通
        if not is_valid:
            count += 1
        # 累计沟通超过2次直接返回
        if count >= 2:
            break
        # 统计有效沟通窗口次数
        if is_valid:
            success += 1
    return count, success


def get_target_objs(object_state=BDTRANSFER_OBJECT_STATE.HAS_SENT_SINGLE,
        span=30, chuck_size=3, status=SINGLE_TYPE.NO_ORDER_FORM, is_surgen=False):
    object_state_condition = []
    if isinstance(object_state, list):
        object_state_condition.extend(object_state)
    else:
        object_state_condition.append(object_state)

    bd_objs = BDTransfer.objects.filter(object_state__in=object_state_condition, current_follow_up_consultant__isnull=False)
    invalid_bd_objs, just_bd_objs = [], []
    for bd_obj in bd_objs:
        # 获取指定手术类型
        _time = get_target_time(bd_obj, status=map_status[bd_obj.object_state])

        if not _time:
            continue

        operation_type = get_target_bdtransfer_operation_type(bd_obj, status=map_status[bd_obj.object_state])

        if operation_type != is_surgen:
            continue

        valid_datetime_range = get_valid_time_window(_time, span, chuck_size)

        if not valid_datetime_range:
            continue

        nums, success = get_valid_nums(bd_obj, valid_datetime_range)

        # 回抛并发邮件
        if nums == 2 or (status == SINGLE_TYPE.HAS_CONSULTATION and nums != 0):
            invalid_bd_objs.append(bd_obj)
        else:  # 只发邮件
            just_bd_objs.append(bd_obj)

        if success == 10 or success == 6:
            invalid_bd_objs.append(bd_obj)

    return invalid_bd_objs, just_bd_objs


def dump(ones, twos):

    second_data_ret = {}
    for obj in ones:
        second_data_ret[obj.id] = obj.current_follow_up_consultant.username

    third_data_ret = {}
    for obj in twos:
        if obj.id in second_data_ret:
            del second_data_ret[obj.id]
        third_data_ret[obj.id] = obj.current_follow_up_consultant.username

    return second_data_ret, third_data_ret


def back_to_public(datas):
    """
    个人 ---> 公池
    :param datas:
    :return:
    """

    user = User.objects.get(id=OPERATION_USER_ID)
    for bd in datas:
        content = u"回抛原因: {}".format(u'超时未转化')
        updates = {"is_assign": False, "assigner": None, 'assigned_time': None,
                   'current_follow_up_consultant': None, "is_back": False, 'pooled_time': datetime.now()}
        for key, value in updates.items():
            setattr(bd, key, value)
        bd.save()
        BDTransferOperationRecord.objects.create(
            bdtransfer=bd, action=OPERATION_ACTION.RETURN_TO_PUBLIC, content=content, operate_user=user
        )


def back_to_back(datas):
    """
    个人 --> 回抛
    :param datas:
    :return:
    """

    user = User.objects.get(id=OPERATION_USER_ID)
    for bd in datas:
        content = u"回抛原因: {}".format(u'超时未转化')
        updates = {"is_assign": False, "assigner": None, 'assigned_time': None,
                   'current_follow_up_consultant': None, "is_back": True, 'pooled_time': datetime.now()}
        for key, value in updates.items():
            setattr(bd, key, value)
        bd.save()
        BDTransferOperationRecord.objects.create(
            bdtransfer=bd, action=OPERATION_ACTION.RETURN, content=content, operate_user=user
        )


@shared_task
def check_clues_second_stage_status():
    dt = tablib.Dataset()
    dt.headers = (u'转诊对象ID', u'当前跟进顾问', u'预警原因')
    now_date_str = datetime.now().strftime('%Y-%m-%d')

    back_to_public_objs, back_to_back_objs = [], []
    # 排单阶段待回抛  和 告警
    single_second_invalid_bd_objs, single_second_just_bd_objs = get_target_objs(
        span=30, chuck_size=3, is_surgen=False,  # 非手术类型
        status=SINGLE_TYPE.NO_ORDER_FORM,
        object_state=[BDTRANSFER_OBJECT_STATE.HAS_SENT_SINGLE, BDTRANSFER_OBJECT_STATE.HAS_MADE_APPOINTMENT],
    )
    single_third_invalid_bd_objs, single_third_just_bd_objs = get_target_objs(
        span=60, chuck_size=3, is_surgen=True,
        status=SINGLE_TYPE.NO_ORDER_FORM,
        object_state=[BDTRANSFER_OBJECT_STATE.HAS_SENT_SINGLE, BDTRANSFER_OBJECT_STATE.HAS_MADE_APPOINTMENT],
    )
    consult_second_invalid_bd_objs, consult_second_just_bd_objs = get_target_objs(
        object_state=BDTRANSFER_OBJECT_STATE.HAS_CONSULTATION, span=30, chuck_size=5,
        status=SINGLE_TYPE.HAS_CONSULTATION,
        is_surgen=False,
    )
    consult_third_invalid_bd_objs, consult_third_just_bd_objs = get_target_objs(
        object_state=BDTRANSFER_OBJECT_STATE.HAS_CONSULTATION, span=60, chuck_size=5,
        status=SINGLE_TYPE.HAS_CONSULTATION,
        is_surgen=True
    )

    single_second_just, single_second_invalid = dump(single_second_just_bd_objs, single_second_invalid_bd_objs)
    consult_second_just, consult_second_invalid = dump(consult_second_just_bd_objs, consult_second_invalid_bd_objs)
    single_third_just, single_third_invalid = dump(single_third_just_bd_objs, single_third_invalid_bd_objs)
    consult_third_just, consult_third_invalid = dump(consult_third_just_bd_objs, consult_third_invalid_bd_objs)

    for id, username in single_second_invalid.iteritems():
        dt.append((
            id,
            username,
            "已派单线索（非手术）转化超时二阶段报警，请尽快转化!", # 已回抛公共池
        ))

    for id, username in single_second_just.iteritems():
        dt.append((
            id,
            username,
            "已派单线索（非手术）转化二阶段报警，请尽快转化，否则将回抛公共池",
        ))

    for id, username in consult_second_just.iteritems():
        dt.append((
            id,
            username,
            "已面诊线索（手术）转化二阶段报警，请尽快转化，否则将转入回抛池",
        ))

    for id, username in consult_second_invalid.iteritems():
        dt.append((
            id,
            username,
            "已面诊线索（非手术）转化超时二阶段报警，请尽快转化!", # 已转入回抛池
        ))

    for id, username in single_third_invalid.iteritems():
        dt.append((
            id,
            username,
            "已派单线索（手术）转化超时三阶段报警，请尽快转化！", #  已回抛公共池
        ))

    for id, username in single_third_just.iteritems():
        dt.append((
            id,
            username,
            "已派单线索（手术）转化三阶段报警，请尽快转化，否则将回抛公共池",
        ))

    for id, username in consult_third_just.iteritems():
        dt.append((
            id,
            username,
            "已面诊线索（手术）转化三阶段报警，请尽快转化，否则将转入回抛池",
        ))

    for id, username in consult_third_invalid.iteritems():
        dt.append((
            id,
            username,
            "已面诊线索（手术）转化超时三阶段报警，请尽快转化", # 已转入回抛池
        ))

    total = len(single_second_just) + len(single_second_invalid) + \
            len(consult_second_just) + len(consult_second_invalid) + len(single_third_just) + \
            len(single_third_invalid) + len(consult_third_just) + len(consult_third_invalid)

    body = u'{date}, 个人池命中监控规则线索数{nums}条, 请注意!'.format(date=now_date_str, nums=total)
    dt.title = u'转诊对象个人池线索监控通知邮件'
    if dt:
        send_export_mail(u'转诊对象个人池线索监控通知邮件', body, to_mail_list, attach_excel=True, dt=dt)

    # back_to_public_objs.extend(single_second_invalid_bd_objs)
    # back_to_public_objs.extend(single_third_invalid_bd_objs)
    # back_to_public(back_to_public_objs)
    #
    # back_to_back_objs.extend(consult_second_invalid_bd_objs)
    # back_to_back_objs.extend(consult_third_invalid_bd_objs)
    # back_to_back(back_to_back_objs)


@shared_task
def check_clues_first_stage_status():
    """
    已排单/已预约,                                 已面诊
    手术   第一  30days  第二 60days
    非手术 第一  30days
    :return:
    """
    now_time = datetime.now()
    single_operation_statify_60_bd_objs = []
    the_first_stage_span, the_second_stage_span = 30, 60
    single_operation_statify_30_bd_objs, single_non_operation_statify_bd_objs = [], []
    bd_objs = BDTransfer.objects.filter(
        object_state__in=[BDTRANSFER_OBJECT_STATE.HAS_SENT_SINGLE, BDTRANSFER_OBJECT_STATE.HAS_MADE_APPOINTMENT],
        current_follow_up_consultant__isnull=False
    )
    for bd_obj in bd_objs:
        single_time = get_target_time(bd_obj, status=map_status[bd_obj.object_state])
        if not single_time:
            continue

        time_delta = (now_time - single_time).days
        operation_type = get_target_bdtransfer_operation_type(bd_obj, status=map_status[bd_obj.object_state])
        if time_delta < the_first_stage_span:
            continue
        if time_delta == the_first_stage_span and operation_type == SUR_OPERATION_TYPE:  # 手术类型
            single_operation_statify_30_bd_objs.append(bd_obj)
        elif time_delta == the_second_stage_span and operation_type == SUR_OPERATION_TYPE:
            single_operation_statify_60_bd_objs.append(bd_obj)
        elif time_delta == the_first_stage_span:  # 非手术类型
            single_non_operation_statify_bd_objs.append(bd_obj)

    consult_operation_statify_60_bd_objs = []
    consult_operation_statify_30_bd_objs, consult_non_operation_statify_bd_objs = [], []
    bd_objs = BDTransfer.objects.filter(object_state=BDTRANSFER_OBJECT_STATE.HAS_CONSULTATION)
    for bd_obj in bd_objs:
        operation_type = get_target_bdtransfer_operation_type(bd_obj, status=SINGLE_TYPE.HAS_CONSULTATION)
        single_time = get_target_time(bd_obj, status=SINGLE_TYPE.HAS_CONSULTATION)

        if not single_time:
            continue

        time_delta = (now_time - single_time).days
        if time_delta < the_first_stage_span:
            continue

        if the_first_stage_span == time_delta and operation_type == SUR_OPERATION_TYPE:  # 手术类型
            consult_operation_statify_30_bd_objs.append(bd_obj)
        elif the_second_stage_span == time_delta and operation_type == SUR_OPERATION_TYPE:
            consult_operation_statify_60_bd_objs.append(bd_obj)
        elif time_delta == the_first_stage_span:
            consult_non_operation_statify_bd_objs.append(bd_obj)

    data = [
        ("已派单线索（手术）转化超时一阶段报警", single_operation_statify_30_bd_objs),
        ("已派单线索（手术）转化超时二阶段报警", single_operation_statify_60_bd_objs),
        ("已面诊线索（手术）转化超时一阶段报警", consult_operation_statify_30_bd_objs),
        ("已面诊线索（手术）转化超时二阶段报警", consult_operation_statify_60_bd_objs),
        ("已派单线索（非手术）转化超时一阶段报警", single_non_operation_statify_bd_objs),
        ("已面诊线索（非手术）转化超时一阶段报警", consult_non_operation_statify_bd_objs),
    ]
    to_send_email(data)


@shared_task
def check_clues_followed_up_within_specified_days():
    """
    检测个人是否在指定天数未跟进
    :return:
    """
    now_date_str = datetime.now().strftime('%Y-%m-%d')
    the_first_seven_days = datetime.now() - timedelta(days=7)
    bd_datas = []
    for bd in BDTransfer.objects.filter(
            is_assign=True, is_back=False,
            pooled_time__lte=the_first_seven_days,
            current_follow_up_consultant__isnull=False,
            potential_assess=USER_POTENTIAL.GENERAL_CUSTOMER).values('id', 'obj.current_follow_up_consultant.username'):
        if BDTransferSingleRecord.objects.filter(dbtransfer_id=bd['id']).exists():
            bd_datas.append(bd)

    dt = tablib.Dataset()
    dt.headers = (u'转诊对象ID', u'当前跟进顾问')
    body = u'{date}, 个人池超时未转化线索数未{nums}条, 请尽快重新分配!'.format(date=now_date_str, nums=len(bd_datas))
    for bd in bd_datas:
        dt.append((
            bd['id'],
            bd['obj.current_follow_up_consultant.username']
        ))

    dt.title = u'转诊对象未转化统计'
    if dt:
        send_export_mail(u'转诊对象未转化统计', body, to_mail_list, attach_excel=True, dt=dt)


@shared_task
def check_public_clues_exceed_specified_number():
    """
    检测线索池数目是否超过指定数额
    :return:
    """
    nums = 0
    now = datetime.now()
    now_date_str = datetime.now().strftime(DATETIME_FMT)

    for bd in BDTransfer.objects.filter(is_assign=False, is_back=False):
        if (now - bd.pooled_time).days >= 7:
            nums += 1
        else:
            continue
    body = u'{date}, 公共池超时积压线索数为{nums}条，请尽快分配!'.format(date=now_date_str, nums=nums)
    send_export_mail(u'转诊公池数量告警邮件!', body, to_mail_list)


def to_send_email(data):
    """
    发送邮件数据组装
    :param data:
    :return:
    """
    nums = 0
    dt = tablib.Dataset()
    has_seen = set()
    dt.headers = (u'转诊对象ID', u'当前跟进顾问', u'预警原因')
    now_date_str = datetime.now().strftime('%Y-%m-%d')
    for desc, objs in data:
        objs_result = []
        if not objs:
            continue

        # 去重处理
        for obj in objs:
            if obj.id in has_seen:
                continue
            has_seen.add(obj.id)
            objs_result.append(obj)

        nums += len(objs_result)
        dt.extend([
            (obj.id, obj.current_follow_up_consultant.username, desc)
            for obj in objs_result
        ])

    body = u'{date}, 个人池命中监控规则线索数{nums}条, 请注意!'.format(date=now_date_str, nums=nums)
    dt.title = u'转诊对象个人池线索监控通知邮件'
    if dt:
        send_export_mail(u'转诊对象个人池线索监控通知邮件', body, to_mail_list, attach_excel=True, dt=dt)

    return True


def get_bdtransfer_results(span, surgen):
    """

    :param span: 时间跨度 30/60
    :param surgen: 手术，非手术
    :return:
    """
    back_to_public_objs = []
    back_to_back_objs = []
    just_remind_objs_for_paidan = []
    just_remind_objs_for_consult = []

    # 获取符合条件的线索
    satsify_bd_objs = BDTransfer.objects.filter(
        current_follow_up_consultant__isnull=False,
        object_state__in=[
            BDTRANSFER_OBJECT_STATE.HAS_SENT_SINGLE,
            BDTRANSFER_OBJECT_STATE.HAS_MADE_APPOINTMENT,
            BDTRANSFER_OBJECT_STATE.HAS_CONSULTATION
        ])

    # 面诊5天一个周期, 排单+预约3天一个周期
    for bd_obj in satsify_bd_objs:
        # 获取线索下面对应状态排单关联的tag_ids, 并根据tag_ids判断属性
        # 获取当前手术类型
        operation_type = get_target_bdtransfer_operation_type(bd_obj, status=map_status[bd_obj.object_state])
        if operation_type != surgen:
            continue

        the_first_single_record_obj = bd_obj.single_records.filter(status=map_status[bd_obj.object_state]).first()
        if not the_first_single_record_obj:
            continue

        if bd_obj.object_state == BDTRANSFER_OBJECT_STATE.HAS_CONSULTATION:
            # 5天一个周期, 一次未跟进就回抛或者(6次都跟进, 但未成单), 回抛到回泡池
            time = the_first_single_record_obj.consultation_time
            valid_datetime_range = get_valid_time_window(time, span, 5)
        else:
            # 3天一个周期, 累计两次未跟进或者(10次都跟进, 但未成单), 回抛到公池
            time = the_first_single_record_obj.single_time
            valid_datetime_range = get_valid_time_window(time, span, 3)

        if not time or not valid_datetime_range:
            continue

        fail, success = get_valid_nums(bd_obj, valid_datetime_range)
        if bd_obj.object_state == BDTRANSFER_OBJECT_STATE.HAS_CONSULTATION:
            # 两种情况: 存在一次未沟通或者6次都沟通, 直接回抛
            if fail != 0 or success == 6:
                back_to_back_objs.append(bd_obj)
            else:  # 只发邮件
                just_remind_objs_for_consult.append(bd_obj)
        else:
            # 两种情况: 累计2次未沟通或者10都沟通, 直接回抛
            if fail == 2 or success == 10:
                back_to_public_objs.append(bd_obj)
            else:  # 只发邮件
                just_remind_objs_for_paidan.append(bd_obj)

    return back_to_public_objs, back_to_back_objs, just_remind_objs_for_paidan, just_remind_objs_for_consult


@shared_task
def check_second_and_third_stage():
    """

    :return:
    """
    to_back, to_pulic = [], []
    # 排单+预约  非手术  30天   3天  累计两次未跟进或者(10次都跟进, 但未成单), 回抛到公池
    # 面诊       非手术  30天   5天  一次未跟进就回抛或者(6次都跟进, 但未成单), 回抛到回泡池
    back_to_public_non_surgen_objs, back_to_back_non_surgen_objs, \
    just_remind_non_surgen__objs_for_paidan, \
    just_remind_non_surgen__objs_for_consult = get_bdtransfer_results(span=30, surgen=False)

    # 排单+预约  手术  60天   3天  累计两次未跟进或者(10次都跟进, 但未成单), 回抛到公池
    # 面诊       手术  60天   5天  一次未跟进就回抛或者(6次都跟进, 但未成单), 回抛到回泡池
    back_to_public_surgen_objs, back_to_back_surgen_objs, \
    just_remind_surgen_objs_for_paidan, \
    just_remind_surgen_objs_for_consult = get_bdtransfer_results(span=60, surgen=True)

    data = [
        ("已派单线索（非手术）转化超时二阶段报警，请尽快转化!", back_to_public_non_surgen_objs),  # 已回抛公共池
        ("已面诊线索（非手术）转化超时二阶段报警，请尽快转化!", back_to_back_non_surgen_objs),  # 已转入回抛池
        ("已派单线索（手术）转化超时三阶段报警，请尽快转化！", back_to_public_surgen_objs), # 已回抛公共池
        ("已面诊线索（手术）转化超时三阶段报警，请尽快转化!", back_to_back_surgen_objs), # 已转入回抛池
        ("已派单线索（非手术）转化二阶段报警，请尽快转化，否则将回抛公共池", just_remind_non_surgen__objs_for_paidan),
        ("已面诊线索（非手术）转化二阶段报警，请尽快转化，否则将转入回抛池", just_remind_non_surgen__objs_for_consult),
        ("已派单线索（手术）转化三阶段报警，请尽快转化，否则将回抛公共池", just_remind_surgen_objs_for_paidan),
        ("已面诊线索（手术）转化三阶段报警，请尽快转化，否则将转入回抛池", just_remind_surgen_objs_for_consult),
    ]
    to_back.extend(back_to_back_non_surgen_objs)
    to_back.extend(back_to_back_surgen_objs)
    to_pulic.extend(back_to_public_non_surgen_objs)
    to_pulic.extend(back_to_public_surgen_objs)

    # 发送邮件
    flag = to_send_email(data)

    # # 回抛公池
    # if to_pulic and flag:
    #     back_to_public(to_pulic)
    #
    # # # 回抛回抛池
    # if to_back and flag:
    #     back_to_back(to_back)