package com.prolog.rdc.tms.app.service.flow.chain;

import cn.hutool.core.util.NumberUtil;
import com.google.common.collect.Lists;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.RestrictionBuilder;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.rdc.tms.app.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillDetailMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillHeaderMapper;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillDetailModel;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillDetailModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.app.proxy.MainDataProxy;
import com.prolog.rdc.tms.app.proxy.UserProxy;
import com.prolog.rdc.tms.app.service.flow.FlowContext;
import com.prolog.rdc.tms.app.service.flow.FlowNodeHandle;
import com.prolog.rdc.tms.app.service.flow.handle.ReturnShipBillAddHandle;
import com.prolog.rdc.tms.app.service.flow.handle.ReturnShipBillCheckHandle;
import com.prolog.rdc.tms.app.service.flow.handle.ReturnShipBillDispatchHandle;
import com.prolog.rdc.tms.app.service.flow.handle.ReturnShipBillReviewHandle;
import com.prolog.rdc.tms.app.service.flow.handle.ReturnShipBillCommitHandle;
import com.prolog.rdc.tms.model.dto.basicData.ItemCheckDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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

/**
 * @author hongbo.pan
 * @date 2022/10/17
 */
@Component
public class ReturnShipBillChain {

    @Value("${prolog.system.username}")
    private String systemUsername;

    @Autowired
    private UserProxy userProxy;

    @Autowired
    private MainDataProxy mainDataProxy;

    @Autowired
    private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

    @Autowired
    private TmsLoadingBillHeaderMapper tmsLoadingBillHeaderMapper;

    @Autowired
    private ReturnShipBillAddHandle returnShipBillAddHandle;

    @Autowired
    private ReturnShipBillCommitHandle returnShipBillCommitHandle;

    @Autowired
    private ReturnShipBillReviewHandle returnShipBillReviewHandle;

    @Autowired
    private ReturnShipBillDispatchHandle returnShipBillDispatchHandle;

    @Autowired
    private ReturnShipBillCheckHandle returnShipBillCheckHandle;

    private List<FlowNodeHandle> buildChain() {
        List<FlowNodeHandle> chain = Lists.newArrayList();
        chain.add(returnShipBillAddHandle);
        chain.add(returnShipBillCommitHandle);
        chain.add(returnShipBillReviewHandle);
        chain.add(returnShipBillDispatchHandle);
        chain.add(returnShipBillCheckHandle);
        return chain;
    }

    public void execute(TmsShipbillHeaderModel tmsShipBillHeaderModel, List<TmsShipbillDetailModel> tmsShipBillDetailModelList) {
        FlowContext context = new FlowContext();
        StringBuilder sb = new StringBuilder();
        sb.append(DataDictionaryConstant.FLOW_CONFIG_ADD)
//                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_ADD_COMMIT)
                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_COMMIT)
//                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_COMMIT_REVIEW)
                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_REVIEW)
//                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_REVIEW_DISPATCH)
                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_DISPATCH)
//                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_DISPATCH_CHECK)
                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_CHECK)
                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_SEND_OFF)
                .append(",").append(DataDictionaryConstant.FLOW_CONFIG_ARRIVE_CONFIRM);
        context.setFlowConfig(sb.toString());
        context.setOriginalTmsShipBillDetailModelList(reCalTmsShipBillDetailModel(tmsShipBillDetailModelList));
        context.setOriginalTmsShipBillHeaderModel(reCalTmsShipBillHeaderModel(tmsShipBillHeaderModel,
                context.getOriginalTmsShipBillDetailModelList()));
        context.setOriginalTmsLoadingBillHeaderModel(getTmsLoadingBillHeaderModel(tmsShipBillHeaderModel.getShipbillId()));
        context.setUserEntity(initUser());
        List<FlowNodeHandle> chain = buildChain();
        chain.forEach(flowNodeHandle -> flowNodeHandle.nodeHandle(context));
    }

    /**
     * 初始化操作人
     * @return
     */
    private UserEntity initUser() {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        UserDTO userDTO = userProxy.getUserInfo(systemUsername);
        UserEntity userEntity = new UserEntity();
        userEntity.setUserid(Long.valueOf(userDTO.getId()));
        userEntity.setUsername(userDTO.getUsername());
        userEntity.setNickname(userDTO.getNickname());
        userEntity.setUserType(userDTO.getType() + "");
        userEntity.setPhone(userDTO.getPhone());
        userEntity.setEmail(userDTO.getEmail());
        userEntity.setEnterpriseId(user.getEnterpriseId());
        userEntity.setEnterpriseName(user.getEnterpriseName());
        return userEntity;
    }

    /**
     * 重算运单明细件重体
     * @param tmsShipBillDetailModelList
     * @return
     */
    private List<TmsShipbillDetailModel> reCalTmsShipBillDetailModel(List<TmsShipbillDetailModel> tmsShipBillDetailModelList) {
        List<Long> itemIdList = tmsShipBillDetailModelList.stream().map(TmsShipbillDetailModel::getItemId).collect(Collectors.toList());
        Map<Long, ItemCheckDTO> itemCheckDTOMap = mainDataProxy.getItemByIdList(itemIdList);
        // 重算件重体
        tmsShipBillDetailModelList = tmsShipBillDetailModelList.stream().peek(shipBillDetailModel -> {
            ItemCheckDTO itemCheckDTO = itemCheckDTOMap.get(shipBillDetailModel.getItemId());
            shipBillDetailModel.setWeight(NumberUtil.mul(shipBillDetailModel.getPcs(), itemCheckDTO.getWeight()));
            shipBillDetailModel.setVolume(NumberUtil.mul(shipBillDetailModel.getPcs(), itemCheckDTO.getVolume()));
        }).collect(Collectors.toList());
        return tmsShipBillDetailModelList;
    }

    /**
     * 重算运单件重体
     * @param tmsShipBillHeaderModel
     * @param tmsShipBillDetailModelList
     * @return
     */
    private TmsShipbillHeaderModel reCalTmsShipBillHeaderModel(TmsShipbillHeaderModel tmsShipBillHeaderModel, List<TmsShipbillDetailModel> tmsShipBillDetailModelList) {
        tmsShipBillHeaderModel.setTotalPcs(tmsShipBillDetailModelList.stream().map(TmsShipbillDetailModel::getPcs).reduce(BigDecimal.ZERO, NumberUtil::add));
        tmsShipBillHeaderModel.setTotalWeight(tmsShipBillDetailModelList.stream().map(TmsShipbillDetailModel::getWeight).reduce(BigDecimal.ZERO, NumberUtil::add));
        tmsShipBillHeaderModel.setTotalVolume(tmsShipBillDetailModelList.stream().map(TmsShipbillDetailModel::getVolume).reduce(BigDecimal.ZERO, NumberUtil::add));
        tmsShipBillHeaderModel.setActualTotalPcs(tmsShipBillHeaderModel.getTotalPcs());
        tmsShipBillHeaderModel.setActualTotalWeight(tmsShipBillHeaderModel.getTotalWeight());
        tmsShipBillHeaderModel.setActualTotalVolume(tmsShipBillHeaderModel.getTotalVolume());
        return tmsShipBillHeaderModel;
    }

    /**
     * 获取运单的派车单
     * @param shipBillId
     * @return
     */
    private TmsLoadingBillHeaderModel getTmsLoadingBillHeaderModel(String shipBillId) {
        Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
        Restriction restriction = new RestrictionBuilder()
                .eq("shipbillId", shipBillId)
                .build();
        criteria.setOrder(Order.newInstance().desc(new String[] { "createtime" }));
        criteria.setRestriction(restriction);
        List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
        String loadingBillId = tmsLoadingBillDetailModelList.get(0).getLoadingBillId();
        return tmsLoadingBillHeaderMapper.findById(loadingBillId, TmsLoadingBillHeaderModel.class);
    }
}
