package cn.iocoder.yudao.module.order.service.batchOrderFeeApply;

import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apollo.core.event.Order.OrderApprovalTypeCheckEvent;
import cn.iocoder.yudao.framework.apollo.core.event.Order.OrderNumberLogEvent;
import cn.iocoder.yudao.framework.common.util.code.CodeUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.framework.http.util.StrUtils;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.BpmCreateServiceFactory;
import cn.iocoder.yudao.module.bpm.enums.WorkFlowEmus;
import cn.iocoder.yudao.module.ecw.dal.dataobject.currency.CurrencyDO;
import cn.iocoder.yudao.module.ecw.service.currency.CurrencyService;
import cn.iocoder.yudao.module.order.dto.OrderBackInfoDto;
import cn.iocoder.yudao.module.order.enums.OrderApprovalTypeResultEnum;
import cn.iocoder.yudao.module.order.service.order.OrderBusinessService;
import cn.iocoder.yudao.module.order.service.order.OrderFeeApplicationService;
import cn.iocoder.yudao.module.order.service.order.OrderQueryService;
import cn.iocoder.yudao.module.order.service.order.OrderService;
import cn.iocoder.yudao.module.order.vo.order.ApplyInfoVO;
import cn.iocoder.yudao.module.order.vo.orderFeeApplication.OrderFeeApplicationCreateReqVO;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.order.vo.batchOrderFeeApply.*;
import cn.iocoder.yudao.module.order.dal.dataobject.batchOrderFeeApply.BatchOrderFeeApplyDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.order.convert.batchOrderFeeApply.BatchOrderFeeApplyConvert;
import cn.iocoder.yudao.module.order.dal.mysql.batchOrderFeeApply.BatchOrderFeeApplyMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.order.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.order.enums.OrderApprovalTypeEnum.expense_apply;
import static cn.iocoder.yudao.module.order.enums.OrderNumberEnum.BFA_NO;

/**
 * 批量费用申请 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
public class BatchOrderFeeApplyServiceImpl extends AbstractService<BatchOrderFeeApplyMapper, BatchOrderFeeApplyDO> implements BatchOrderFeeApplyService {

    @Resource
    private BatchOrderFeeApplyMapper batchOrderFeeApplyMapper;
    @Resource
    private OrderQueryService orderQueryService;
    @Resource
    private OrderFeeApplicationService orderFeeApplicationService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private BpmCreateServiceFactory bpmCreateServiceFactory;
    @Resource
    private CurrencyService currencyService;
    @Resource
    @Lazy
    private OrderBusinessService orderBusinessService;
    @Resource
    private OrderService orderService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createBatchOrderFeeApply(BatchOrderFeeApplyCreateReqVO createReqVO) {
        if (Objects.isNull(createReqVO.getBatchApplyDetailsInfoVO()) || CollectionUtil.isEmpty(createReqVO.getBatchApplyDetailsInfoVO().getOrderFeeDetailsVOList())) {
            throw exception(BATCH_ORDER_FEE_APPLY_INFO_NOT_EXISTS);
        }
        List<Long> orderIds = new ArrayList<>();
        for (BatchOrderFeeDetailsVO batchOrderFeeDetailsVO : createReqVO.getBatchApplyDetailsInfoVO().getOrderFeeDetailsVOList()) {
            OrderApprovalTypeCheckEvent approvalTypeCheckEvent = new OrderApprovalTypeCheckEvent(batchOrderFeeDetailsVO.getOrderId(), null, expense_apply.getValue(), null, false);
            applicationContext.publishEvent(approvalTypeCheckEvent);
            if (approvalTypeCheckEvent.getResult()) {
                throw exception(ORDER_IS_APPROVAL_IN_PROCESS);
            }
            orderIds.add(batchOrderFeeDetailsVO.getOrderId());
        }
        // 插入
        BatchOrderFeeApplyDO batchOrderFeeApply = BatchOrderFeeApplyConvert.INSTANCE.convert(createReqVO);
        batchOrderFeeApply.setOrderIds(orderIds.stream().map(String::valueOf).collect(Collectors.joining(StrUtil.COMMA)));
        batchOrderFeeApply.setDetails(JsonUtils.toJsonString(createReqVO.getBatchApplyDetailsInfoVO()));
        // 批量费用申请编号BFA+年份+月份+五位数；BFA240100001
        String no = this.generateNo();
        batchOrderFeeApply.setNo(no);

        batchOrderFeeApplyMapper.insert(batchOrderFeeApply);
        // 发起流程
        String formId = bpmCreateServiceFactory.createBmp(SecurityFrameworkUtils.getLoginUserId(),
                batchOrderFeeApply.getId(), WorkFlowEmus.BATCH_ORDER_FREE_APPLY.getKey(), batchOrderFeeApply.getNo(), createReqVO.getCopyUserId());
        batchOrderFeeApply.setFormId(formId);
        batchOrderFeeApplyMapper.updateById(batchOrderFeeApply);

        for (BatchOrderFeeDetailsVO batchOrderFeeDetailsVO : createReqVO.getBatchApplyDetailsInfoVO().getOrderFeeDetailsVOList()) {
            List<ApplyInfoVO> list = new ArrayList<>();
            for (OrderFeeApplicationCreateReqVO orderFeeApplicationCreateReqVO : batchOrderFeeDetailsVO.getOrderFeeApplicationBaseVOList()) {
                DictDataRespDTO feeDictDataFromCache = DictFrameworkUtils.getDictDataFromCache(DictTypeConstants.RECEIVABLE_FEE_TYPE, String.valueOf(orderFeeApplicationCreateReqVO.getFeeType()));
                DictDataRespDTO payDictDataFromCache = DictFrameworkUtils.getDictDataFromCache(DictTypeConstants.PAYMENT_TYPE, String.valueOf(orderFeeApplicationCreateReqVO.getPayType()));
                CurrencyDO currency = currencyService.getCurrency(orderFeeApplicationCreateReqVO.getApplicationFeeCurrency());
                String value = "%s: 金额[%s%s], 付款类型[%s], 付款人[%s]";
                ApplyInfoVO applyInfoVO = new ApplyInfoVO();
                applyInfoVO.setName(String.format("编号[%s]的批量订单费用申请", no));
                applyInfoVO.setNewValue(String.format(value, feeDictDataFromCache.getLabel().concat("/").concat(feeDictDataFromCache.getLabelEn()), orderFeeApplicationCreateReqVO.getApplicationFee().toString(),
                        currency.getTitleZh().concat("/").concat(currency.getTitleEn()),
                        payDictDataFromCache.getLabel().concat("/").concat(payDictDataFromCache.getLabelEn()),
                        orderFeeApplicationCreateReqVO.getPayer() == 1 ? "发货人" : "收货人"));
                list.add(applyInfoVO);
            }
            orderBusinessService.addOrderOperateLog(batchOrderFeeDetailsVO.getOrderId(), "", "批量提交费用申请", list);
            orderService.updateStatus(batchOrderFeeDetailsVO.getOrderId(), null, null, null, null, null, OrderApprovalTypeResultEnum.expense_apply_batch_order_processing.getType(), OrderApprovalTypeResultEnum.expense_apply_batch_order_processing.getDesc());
        }
        // TODO 这里是多订单进行的批量审批，没有将审批加入到订单审批业务中，后续看业务是否需要将订单细分审批任务
        // 返回
        return batchOrderFeeApply.getId();
    }

    private static final String RECEIPT_NEW_NUMBER = "batch:order:fee:apply";

    /**
     * 批量费用申请编号BFA+年份+月份+五位数；BFA240100001
     */
    private String generateNo() {
        OrderNumberLogEvent event = new OrderNumberLogEvent();
        event.setType(BFA_NO.getType());
        event.setNumberKey(RECEIPT_NEW_NUMBER);
        applicationContext.publishEvent(event);
        String no = CodeUtils.getOddBatchOrderFeeApplyNumbers(event.getNumber());
        // 更新批量订单费用申请编号最新缓存
        // 待将最新编号持久化
        event.setNewNumber(no);
        applicationContext.publishEvent(event);
        return no;
    }

    @Override
    public BatchOrderFeeApplyBackVO getBatchOrderFeeApply(Long id) {
        BatchOrderFeeApplyDO batchOrderFeeApply = batchOrderFeeApplyMapper.selectById(id);
        if (Objects.isNull(batchOrderFeeApply)) {
            throw exception(BATCH_ORDER_FEE_APPLY_NOT_EXISTS);
        }
        BatchOrderFeeApplyBackVO backVO = BatchOrderFeeApplyConvert.INSTANCE.convert(batchOrderFeeApply);
        if (StrUtils.isNotBlank(backVO.getDetails())) {
            BatchApplyDetailsInfoVO batchApplyDetailsInfoVO = JsonUtils.parseObject(batchOrderFeeApply.getDetails(), BatchApplyDetailsInfoVO.class);
            if (batchApplyDetailsInfoVO != null && CollectionUtil.isNotEmpty(batchApplyDetailsInfoVO.getOrderFeeDetailsVOList())) {
                for (BatchOrderFeeDetailsVO batchOrderFeeDetailsVO : batchApplyDetailsInfoVO.getOrderFeeDetailsVOList()) {
                    OrderBackInfoDto orderBackVO = orderQueryService.info(batchOrderFeeDetailsVO.getOrderId());
                    batchOrderFeeDetailsVO.setOrderBackVO(orderBackVO);
                }
            }
            backVO.setBatchApplyDetailsInfoVO(batchApplyDetailsInfoVO);
        }
        return backVO;
    }

    @Override
    public List<BatchOrderFeeApplyDO> getBatchOrderFeeApplyList(Collection<Long> ids) {
        return batchOrderFeeApplyMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<BatchOrderFeeApplyBackVO> getBatchOrderFeeApplyPage(BatchOrderFeeApplyQueryVO query, PageVO page) {

        IPage<BatchOrderFeeApplyBackVO> mpPage = MyBatisUtils.buildPage(page);
        long total = batchOrderFeeApplyMapper.batchOrderFeeApplyCount(query);
        int start = (page.getPage() - 1) * page.getRows();
        int size = page.getRows();
        List<BatchOrderFeeApplyBackVO> list = batchOrderFeeApplyMapper.batchOrderFeeApplyList(start, size, query);
        return new PageResult<>(list, total, mpPage.getSize(), page.getPage(), (total + mpPage.getSize() - 1) / mpPage.getSize());
    }

    @Override
    public List<BatchOrderFeeApplyDO> getBatchOrderFeeApplyList(BatchOrderFeeApplyQueryVO query) {
        return batchOrderFeeApplyMapper.selectList(query);
    }

    @Override
    public BatchOrderFeeApplyBackVO getInfoByFormId(String formId) {
        BatchOrderFeeApplyDO batchOrderFeeApply = batchOrderFeeApplyMapper.selectOne(new LambdaQueryWrapper<BatchOrderFeeApplyDO>()
                .eq(BatchOrderFeeApplyDO::getFormId, formId).orderByDesc(BatchOrderFeeApplyDO::getId).last("limit 1"));
        if (Objects.isNull(batchOrderFeeApply)) {
            throw exception(BATCH_ORDER_FEE_APPLY_NOT_EXISTS);
        }
        BatchOrderFeeApplyBackVO backVO = BatchOrderFeeApplyConvert.INSTANCE.convert(batchOrderFeeApply);
        if (StrUtils.isNotBlank(backVO.getDetails())) {
            BatchApplyDetailsInfoVO batchApplyDetailsInfoVO = JsonUtils.parseObject(batchOrderFeeApply.getDetails(), BatchApplyDetailsInfoVO.class);
            if (batchApplyDetailsInfoVO != null && CollectionUtil.isNotEmpty(batchApplyDetailsInfoVO.getOrderFeeDetailsVOList())) {
                for (BatchOrderFeeDetailsVO batchOrderFeeDetailsVO : batchApplyDetailsInfoVO.getOrderFeeDetailsVOList()) {
                    OrderBackInfoDto orderBackVO = orderQueryService.info(batchOrderFeeDetailsVO.getOrderId());
                    batchOrderFeeDetailsVO.setOrderBackVO(orderBackVO);
                }
            }
            backVO.setBatchApplyDetailsInfoVO(batchApplyDetailsInfoVO);
        }
        return backVO;
    }

    @Override
    public List<OrderBackInfoDto> getOrderListByIds(List<Long> orderIds) {
        return orderIds.stream().map(orderId -> orderQueryService.info(orderId)).collect(Collectors.toList());
    }

    @Override
    public void batchOrderFeeApplyCallback(String id, Integer result) {
        if (result == 1) {
            return;
        }
        BatchOrderFeeApplyDO batchOrderFeeApply = batchOrderFeeApplyMapper.selectById(id);
        if (Objects.isNull(batchOrderFeeApply)) {
            throw exception(BATCH_ORDER_FEE_APPLY_NOT_EXISTS);
        }
        String audit = String.valueOf(SecurityFrameworkUtils.getLoginUserId());
        Date now = new Date();
        batchOrderFeeApply.setAudit(audit);
        batchOrderFeeApply.setAuditTime(now);
        batchOrderFeeApply.setUpdater(audit);
        batchOrderFeeApply.setUpdateTime(now);
        // 通用订单批量费用申请
        OrderApprovalTypeResultEnum orderApprovalTypeResultEnum = OrderApprovalTypeResultEnum.typeAndResultOf(42, result);
        if (result == 3 || result == 4) {
            batchOrderFeeApply.setState(result);
            batchOrderFeeApplyMapper.updateById(batchOrderFeeApply);
            BatchApplyDetailsInfoVO batchApplyDetailsInfoVO = JsonUtils.parseObject(batchOrderFeeApply.getDetails(), BatchApplyDetailsInfoVO.class);
            if (batchApplyDetailsInfoVO != null && CollectionUtil.isNotEmpty(batchApplyDetailsInfoVO.getOrderFeeDetailsVOList())) {
                for (BatchOrderFeeDetailsVO batchOrderFeeDetailsVO : batchApplyDetailsInfoVO.getOrderFeeDetailsVOList()) {
                    List<ApplyInfoVO> list = new ArrayList<>();
                    for (OrderFeeApplicationCreateReqVO orderFeeApplicationCreateReqVO : batchOrderFeeDetailsVO.getOrderFeeApplicationBaseVOList()) {
                        DictDataRespDTO feeDictDataFromCache = DictFrameworkUtils.getDictDataFromCache(DictTypeConstants.RECEIVABLE_FEE_TYPE, String.valueOf(orderFeeApplicationCreateReqVO.getFeeType()));
                        DictDataRespDTO payDictDataFromCache = DictFrameworkUtils.getDictDataFromCache(DictTypeConstants.PAYMENT_TYPE, String.valueOf(orderFeeApplicationCreateReqVO.getPayType()));
                        CurrencyDO currency = currencyService.getCurrency(orderFeeApplicationCreateReqVO.getApplicationFeeCurrency());
                        String value = "%s: 金额[%s%s], 付款类型[%s], 付款人[%s]";
                        ApplyInfoVO applyInfoVO = new ApplyInfoVO();
                        String name = String.format(result == 3?"编号[%s]的批量订单费用申请拒绝":"编号[%s]的批量订单费用申请取消", batchOrderFeeApply.getNo());
                        applyInfoVO.setName(name);
                        applyInfoVO.setNewValue(String.format(value, feeDictDataFromCache.getLabel().concat("/").concat(feeDictDataFromCache.getLabelEn()), orderFeeApplicationCreateReqVO.getApplicationFee().toString(),
                                currency.getTitleZh().concat("/").concat(currency.getTitleEn()),
                                payDictDataFromCache.getLabel().concat("/").concat(payDictDataFromCache.getLabelEn()),
                                orderFeeApplicationCreateReqVO.getPayer() == 1 ? "发货人" : "收货人"));
                        list.add(applyInfoVO);
                    }
                    orderBusinessService.addOrderOperateLog(batchOrderFeeDetailsVO.getOrderId(), "", "批量提交费用申请", list);

                    orderService.updateStatus(batchOrderFeeDetailsVO.getOrderId(), null, null, null, null, null, 0, orderApprovalTypeResultEnum.getDesc());
                }
            }
            return;
        }
        if (StrUtils.isNotBlank(batchOrderFeeApply.getDetails())) {
            BatchApplyDetailsInfoVO batchApplyDetailsInfoVO = JsonUtils.parseObject(batchOrderFeeApply.getDetails(), BatchApplyDetailsInfoVO.class);
            if (Objects.isNull(batchApplyDetailsInfoVO) || CollectionUtil.isEmpty(batchApplyDetailsInfoVO.getOrderFeeDetailsVOList())) {
                throw exception(BATCH_ORDER_FEE_APPLY_INFO_NOT_EXISTS);
            }
            for (BatchOrderFeeDetailsVO batchOrderFeeDetailsVO : batchApplyDetailsInfoVO.getOrderFeeDetailsVOList()) {
                // TODO 保存订单费用申请信息
                orderFeeApplicationService.saveFeeBatchApplication(batchOrderFeeDetailsVO.getOrderId(),
                        batchOrderFeeDetailsVO.getOrderFeeApplicationBaseVOList(),
                        batchOrderFeeApply.getCreator(),
                        audit,
                        now,
                        batchOrderFeeApply.getFormId()
                );
                List<ApplyInfoVO> list = new ArrayList<>();
                for (OrderFeeApplicationCreateReqVO orderFeeApplicationCreateReqVO : batchOrderFeeDetailsVO.getOrderFeeApplicationBaseVOList()) {
                    DictDataRespDTO feeDictDataFromCache = DictFrameworkUtils.getDictDataFromCache(DictTypeConstants.RECEIVABLE_FEE_TYPE, String.valueOf(orderFeeApplicationCreateReqVO.getFeeType()));
                    DictDataRespDTO payDictDataFromCache = DictFrameworkUtils.getDictDataFromCache(DictTypeConstants.PAYMENT_TYPE, String.valueOf(orderFeeApplicationCreateReqVO.getPayType()));
                    CurrencyDO currency = currencyService.getCurrency(orderFeeApplicationCreateReqVO.getApplicationFeeCurrency());
                    String value = "%s: 金额[%s%s], 付款类型[%s], 付款人[%s]";
                    ApplyInfoVO applyInfoVO = new ApplyInfoVO();
                    applyInfoVO.setName(String.format("编号[%s]的批量订单费用申请通过", batchOrderFeeApply.getNo()));
                    applyInfoVO.setNewValue(String.format(value, feeDictDataFromCache.getLabel().concat("/").concat(feeDictDataFromCache.getLabelEn()), orderFeeApplicationCreateReqVO.getApplicationFee().toString(),
                            currency.getTitleZh().concat("/").concat(currency.getTitleEn()),
                            payDictDataFromCache.getLabel().concat("/").concat(payDictDataFromCache.getLabelEn()),
                            orderFeeApplicationCreateReqVO.getPayer() == 1 ? "发货人" : "收货人"));
                    list.add(applyInfoVO);
                }
                orderBusinessService.addOrderOperateLog(batchOrderFeeDetailsVO.getOrderId(), "", "批量提交费用申请", list);
                orderService.updateStatus(batchOrderFeeDetailsVO.getOrderId(), null, null, null, null, null, 0, orderApprovalTypeResultEnum.getDesc());
            }
        }
    }
}
