package cn.superdesk.uniorder.service.invoice.supplier.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.superdesk.uniorder.common.enums.invoice.supplier.InvoiceApplySupplierInvoiceProgressingStatusEnum;
import cn.superdesk.uniorder.common.enums.invoice.supplier.InvoiceApplySupplierReceiveInvoiceStatusEnum;
import cn.superdesk.uniorder.common.lamda.AnLamdaUtils;
import cn.superdesk.uniorder.common.numerical.AnBeanUtils;
import cn.superdesk.uniorder.common.numerical.AnStringUtils;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dao.entity.invoice.supplier.InvoiceApplySupplier;
import cn.superdesk.uniorder.dto.param.invoice.supplier.status.InvoiceApplySupplierOpReceiveInvoiceStatusForm;
import cn.superdesk.uniorder.dto.param.invoice.supplier.status.InvoiceApplySupplierOpReceiveInvoiceStatusFormInnerListItem;
import cn.superdesk.uniorder.executor.scheduler.kafka._thirdpart.qchjc.QchjcStatementKafkaEventPublisher;
import cn.superdesk.uniorder.executor.scheduler.kafka._thirdpart.qchjc.dto.accounting.customer.QchjcCustomerStatementEventSingleStructVo;
import cn.superdesk.uniorder.executor.scheduler.kafka._thirdpart.qchjc.dto.accounting.supplier.QchjcSupplierStatementEvent;
import cn.superdesk.uniorder.executor.scheduler.kafka._thirdpart.qchjc.dto.accounting.supplier.QchjcSupplierStatementEventMultipleStructVo;
import cn.superdesk.uniorder.executor.scheduler.kafka._thirdpart.qchjc.dto.accounting.supplier.QchjcSupplierStatementEventSingleStructVo;
import cn.superdesk.uniorder.pattern.state.invoice.supplier.invoiceApplySupplier.receiveInvoiceStatus.context.InvoiceApplySupplierFieldReceiveInvoiceStatusContext;
import cn.superdesk.uniorder.service.accounting.unified.supplier.AccountingUnifiedSupplierService;
import cn.superdesk.uniorder.service.invoice.supplier.InvoiceApplySupplierFieldReceiveInvoiceStatusService;
import cn.superdesk.uniorder.service.invoice.supplier.InvoiceApplySupplierService;
import cn.superdesk.uniorder.service.invoice.supplier.InvoiceApplySupplierXGoodsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
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 InvoiceApplySupplierFieldReceiveInvoiceStatusServiceImpl implements InvoiceApplySupplierFieldReceiveInvoiceStatusService {

    @Autowired
    private InvoiceApplySupplierService       invoiceApplySupplierService;
    @Autowired
    private InvoiceApplySupplierXGoodsService invoiceApplySupplierXGoodsService;

    @Autowired
    private AccountingUnifiedSupplierService accountingUnifiedSupplierService;

    /**************************************** superdesk-uniorder-executor start ****************************************/

    @Autowired
    private QchjcStatementKafkaEventPublisher qchjcStatementEventPublisher;

    /**************************************** superdesk-uniorder-executor   end ****************************************/

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

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

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

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

        forUpdate.setReceiveInvoiceStatus(InvoiceApplySupplierReceiveInvoiceStatusEnum.未收票.getKey());

        invoiceApplySupplierService.updateInvoiceApplySupplierByPrimaryKeySelective(forUpdate);
    }

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

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

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

        forUpdate.setReceiveInvoiceStatus(InvoiceApplySupplierReceiveInvoiceStatusEnum.已收票.getKey());

        invoiceApplySupplierService.updateInvoiceApplySupplierByPrimaryKeySelective(forUpdate);
    }

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


        DateTime now = DateUtil.date();

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

        entitys.forEach(entity -> {

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

            InvoiceApplySupplierOpReceiveInvoiceStatusFormInnerListItem formTmp = shortcut.get(entity.getId());

            // 发票号
            if (ObjectUtil.isNotNull(formTmp) && CollUtil.isNotEmpty(formTmp.getInvoiceNumber())) {
                forUpdate.setInvoiceNumber(AnStringUtils.stringListConvertToString(formTmp.getInvoiceNumber()));
            }
            // 附件
            forUpdate.setAttachmentUploadFilesUids(AnStringUtils.stringListConvertToString(formTmp.getUids()));

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

            forUpdate.setReceiveInvoiceStatus(InvoiceApplySupplierReceiveInvoiceStatusEnum.已收票.getKey());

            forUpdate.setReceiveInvoiceUserId(loginSysUser.getSysUserId());
//			forUpdate.setReceiveInvoiceUserName(loginSysUser.getFullName());
            forUpdate.setReceiveInvoiceTime(now);

            // 进入下一个流程
            forUpdate.setInvoiceStatus(InvoiceApplySupplierInvoiceProgressingStatusEnum.待付款.getKey());

            invoiceApplySupplierService.updateInvoiceApplySupplierByPrimaryKeySelective(forUpdate);
        });

        List<Long> processInvoiceApplyIds    = entitys.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getId())).map(o -> o.getId()).collect(Collectors.toList());
        List<Long> processAccountingOrderIds = invoiceApplySupplierXGoodsService.getAffectedAccountingOrderIdsByInvoiceApplyIds(processInvoiceApplyIds);

        processAccountingOrderIds.forEach(accountingOrderId -> {
            accountingUnifiedSupplierService.updateFieldInvoiceStatus(accountingOrderId, InvoiceApplySupplierInvoiceProgressingStatusEnum.待付款, loginSysUser);
        });


        /**************************************** 触发事件点 start ****************************************/

        // 触发事件点;集采账单状态推送 TODO
        // 1. 来源于“企业商城”的对账单在**“积分结算-发票登记管理-【收票登记】”成功时**：若该对账单所有有效的开票申请的申请状态均为“待付款”时；
//        List<QchjcSupplierStatementEventSingleStructVo> eventSingleStructVoList = AnBeanUtils.copy(form.getSubmitList(), QchjcSupplierStatementEventSingleStructVo.class);
        List<QchjcSupplierStatementEventSingleStructVo> eventSingleStructVoList = new ArrayList<>();
        form.getSubmitList().forEach(item -> {
            eventSingleStructVoList.add(
                    QchjcSupplierStatementEventSingleStructVo
                            .builder()

                            .invoiceApplyId(item.getInvoiceApplyId())
                            .invoiceApplySn(item.getInvoiceApplySn())
                            .accountingOrderId(item.getAccountingOrderId())
                            .accountingOrderSn(item.getAccountingOrderSn())

                            .build()
            );
        });

        qchjcStatementEventPublisher.supplierStatementEventReceiveInvoiceStatusSync(
                QchjcSupplierStatementEvent
                        .builder()
                        .msg("供应商结算v2.3-发票登记管理-op收票登记-op确认收票")

                        .multipleStructVo(
                                QchjcSupplierStatementEventMultipleStructVo
                                        .builder()
                                        .items(eventSingleStructVoList)
                                        .build()
                        )

                        .loginSysUser(JSONUtil.toJsonStr(loginSysUser))
                        .touchTime(now)

                        .build()
        );

        /**************************************** 触发事件点   end ****************************************/
    }

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


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

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

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

    // 状态流转为 已收票(1, "已收票")
    public void opReceive(List<InvoiceApplySupplier> entitys, InvoiceApplySupplierOpReceiveInvoiceStatusForm form, LoginSysUser loginSysUser) {
        InvoiceApplySupplierFieldReceiveInvoiceStatusContext context = new InvoiceApplySupplierFieldReceiveInvoiceStatusContext(entitys, form, loginSysUser);
        context.opReceive();
    }

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