package cn.superdesk.uniorder.service.invoice.customer.state.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.superdesk.uniorder.common.bizScene.invoice.common.InvoiceTypeScene;
import cn.superdesk.uniorder.common.enums.invoice.customer.InvoiceApplyCustomerInvoiceProgressingStatusEnum;
import cn.superdesk.uniorder.common.enums.invoice.customer.InvoiceApplyCustomerReceiveInvoiceStatusEnum;
import cn.superdesk.uniorder.common.numerical.AnStringUtils;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApply;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.InvoiceApplyCustomerOpReceiveInvoiceStatusForm;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.InvoiceApplyCustomerOpReceiveInvoiceStatusFormInnerListItem;
import cn.superdesk.uniorder.pattern.state.invoice.customer.invoiceApply.receiveInvoiceStatus.context.InvoiceApplyFieldReceiveInvoiceStatusContext;
import cn.superdesk.uniorder.service.invoice.customer.state.InvoiceApplyCustomerFieldReceiveInvoiceStatusService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyCustomerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: 简易状态机 星型结构
 * @Author: linjinyu
 * @CreateDate: 10/12/20 4:28 PM
 * @UpdateUser: linjinyu
 * @UpdateDate: 10/12/20 4:28 PM
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
@Service
public class InvoiceApplyCustomerFieldReceiveInvoiceStatusServiceImpl implements InvoiceApplyCustomerFieldReceiveInvoiceStatusService {

    @Autowired
    private InvoiceApplyCustomerService invoiceApplyService;

    /****************************************** 状态机 公共方法 机内使用 实际流转 重用 start ******************************************/

    // 状态流转为 未领票(0, "未领票")
    public void opInitByStateMachine(InvoiceApply entity, LoginSysUser loginSysUser) {

        InvoiceApply forUpdate = new InvoiceApply();
        forUpdate.setId(entity.getId());

        // TODO 更新状态逻辑...

        forUpdate.setReceiveInvoiceStatus(InvoiceApplyCustomerReceiveInvoiceStatusEnum.未领票.getKey());

        forUpdate.setReceiveInvoiceUserId(loginSysUser.getSysUserId());
        forUpdate.setReceiveInvoiceTime(DateUtil.date());

        invoiceApplyService.updateInvoiceApplyByPrimaryKeySelective(forUpdate);
    }

    // 状态流转为 已领票(1, "已领票")
    public void opReceiveByStateMachine(InvoiceApply entity, LoginSysUser loginSysUser) {

        InvoiceApply forUpdate = new InvoiceApply();
        forUpdate.setId(entity.getId());

        // TODO 更新状态逻辑...
        forUpdate.setInvoiceStatus(InvoiceApplyCustomerInvoiceProgressingStatusEnum.待寄票.getKey());
        forUpdate.setInvoiceProgressingUserId(loginSysUser.getSysUserId());
        forUpdate.setInvoiceProgressingTime(DateUtil.date());


        forUpdate.setReceiveInvoiceStatus(InvoiceApplyCustomerReceiveInvoiceStatusEnum.已领票.getKey());
        forUpdate.setReceiveInvoiceUserId(loginSysUser.getSysUserId());
        forUpdate.setReceiveInvoiceTime(DateUtil.date());

        forUpdate.setUpdateUserId(loginSysUser.getSysUserId());
        forUpdate.setUpdateTime(DateUtil.date());

        invoiceApplyService.updateInvoiceApplyByPrimaryKeySelective(forUpdate);
    }

    // 状态流转为 已领票(1, "已领票")
    public void opReceiveByStateMachine(List<InvoiceApply> entitys, InvoiceApplyCustomerOpReceiveInvoiceStatusForm form, LoginSysUser loginSysUser) {

        /**
         *  key invoiceApplyId
         */
        Map<Long, InvoiceApplyCustomerOpReceiveInvoiceStatusFormInnerListItem> shortcut = form.getSubmitList()
                .stream()
                .collect(
                        Collectors.toMap(
                                InvoiceApplyCustomerOpReceiveInvoiceStatusFormInnerListItem::getInvoiceApplyId,
                                v -> v,
                                (k, v) -> v
                        )
                );

        DateTime now = DateUtil.date();
        entitys.forEach(invoiceApplyCustomerEntity -> {

            InvoiceApply forUpdate = new InvoiceApply();
            forUpdate.setId(invoiceApplyCustomerEntity.getId());

            /**************************************** 逻辑优化 20220510 start ****************************************/

            // 原本逻辑为 op运营领票 深圳航信电子发票 前端是不会传发票号的 shortcut 是为了 保证 entitys与submit的对上
            // 优化逻辑为 在原本基础上添加 是否需求领票登记[发票号]判定

            if (ArrayUtil.contains(
                    InvoiceTypeScene.modesV2_1_Array_SceneNeedOpReceive(),
                    invoiceApplyCustomerEntity.getInvoiceMode())
            ) {
                // 此处为前端提交的 是为了 保证 entitys与submit的对上
                InvoiceApplyCustomerOpReceiveInvoiceStatusFormInnerListItem formTmp = shortcut.get(invoiceApplyCustomerEntity.getId());

                if (ObjectUtil.isNotNull(formTmp) && CollUtil.isNotEmpty(formTmp.getInvoiceNumber())) {
                    forUpdate.setInvoiceNumber(AnStringUtils.stringListConvertToString(formTmp.getInvoiceNumber()));
                }
            }

            /**************************************** 逻辑优化 20220510  end ****************************************/

            // TODO 更新状态逻辑...


            /**************************************** 逻辑冲突解决 20220510 start ****************************************/

//            【【结算中心-测试环境】积分结算-发票管理-CAA2022051094482432-混合开票-线下寄票后-电子票申请状态错误】
//            https://www.tapd.cn/33003868/bugtrace/bugs/view?bug_id=1133003868001005105

            // 解决办法 添加 op运营领票 是否需求领票登记判定 需领票登记的为 [线下开票][深圳航信纸质发票]
            if (ArrayUtil.contains(
                    InvoiceTypeScene.modesV2_1_Array_SceneNeedOpReceive(),
                    invoiceApplyCustomerEntity.getInvoiceMode())
            ) {

                forUpdate.setReceiveInvoiceStatus(InvoiceApplyCustomerReceiveInvoiceStatusEnum.已领票.getKey());
                forUpdate.setReceiveInvoiceUserId(loginSysUser.getSysUserId());
                forUpdate.setReceiveInvoiceTime(now);

                forUpdate.setInvoiceStatus(InvoiceApplyCustomerInvoiceProgressingStatusEnum.待寄票.getKey());
                forUpdate.setInvoiceProgressingUserId(loginSysUser.getSysUserId());
                forUpdate.setInvoiceProgressingTime(now);

            }

            /**************************************** 逻辑冲突解决 20220510  end ****************************************/

            forUpdate.setUpdateUserId(loginSysUser.getSysUserId());
            forUpdate.setUpdateTime(now);

            invoiceApplyService.updateInvoiceApplyByPrimaryKeySelective(forUpdate);
        });
    }

    /****************************************** 状态机 公共方法 机内使用 实际流转 重用   end ******************************************/


    /****************************************** 状态机 外部使用 类门面 start ******************************************/

    // 状态流转为 未领票(0, "未领票")
    public void opInit(InvoiceApply entity, LoginSysUser loginSysUser) {
        InvoiceApplyFieldReceiveInvoiceStatusContext context = new InvoiceApplyFieldReceiveInvoiceStatusContext(entity, loginSysUser);
        context.opInit();
    }

    // 状态流转为 已领票(1, "已领票")
    public void opReceive(InvoiceApply entity, LoginSysUser loginSysUser) {
        InvoiceApplyFieldReceiveInvoiceStatusContext context = new InvoiceApplyFieldReceiveInvoiceStatusContext(entity, loginSysUser);
        context.opReceive();
    }

    // 状态流转为 已领票(1, "已领票")
    public void opReceive(List<InvoiceApply> entitys, InvoiceApplyCustomerOpReceiveInvoiceStatusForm form, LoginSysUser loginSysUser) {
        InvoiceApplyFieldReceiveInvoiceStatusContext context = new InvoiceApplyFieldReceiveInvoiceStatusContext(entitys, form, loginSysUser);
        context.opReceive();
    }

    /****************************************** 状态机 外部使用 类门面   end ******************************************/
}
