package com.prolog.cs.biz.outbound.service.strategy;

import com.prolog.cs.biz.outbound.resource.StrategyResource;
import com.prolog.cs.biz.outbound.service.strategy.handles.IStrategyHandle;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.ParameterException;
import com.prolog.framework.utils.ObjectUtils;
import com.prolog.framework.utils.StringUtils;
import com.prolog.upcloud.base.strategy.model.BusinessControl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @program: upcloud-base-wh-outbound
 * @description:
 * @author: Huanglh
 * @create: 2022-01-11 09:38
 **/
@Service
public class StrategySelector {
    @Autowired
    private UserTemplate userTemplate;

    @Autowired
    private StrategyResource strategyResource;

    @Autowired
    private StrategyFactory strategyFactory;

    public IStrategyHandle selectHandle(List<STRATEGY_CODE> inputCods, String warehouseId, String point) {
        UserDTO userDTO = userTemplate.getUserDTO();
        if (ObjectUtils.isNull(userDTO)) {
            throw new BizException("登入用户信息获取失败");
        }
        String enterpriseId = userDTO.getEnterpriseId();
        return this.selectHandle(inputCods, enterpriseId, warehouseId, point, null, null);
    }

    public IStrategyHandle selectHandle(List<STRATEGY_CODE> inputCods, String enterpriseId, String warehouseId, String point) {
        return this.selectHandle(inputCods, enterpriseId, warehouseId, point, null, null);
    }

    public IStrategyHandle selectHandle(List<STRATEGY_CODE> inputCods, String enterpriseId, String warehouseId, String point,
                                        String cargoOwnerId) {
        return this.selectHandle(inputCods, enterpriseId, warehouseId, point, cargoOwnerId, null);
    }

    /**
     * 配置操作选择器
     * 如果传入多个配置，只返回列表第一个 strategy code 的操作实例
     *
     * @param inputCods
     * @param enterpriseId
     * @param warehouseId
     * @param point
     * @param cargoOwnerId
     * @param bldgId
     * @return
     */
    public IStrategyHandle selectHandle(List<STRATEGY_CODE> inputCods, String enterpriseId, String warehouseId, String point,
                                        String cargoOwnerId, String bldgId) {
        // 获取所有的业务配置参数内容，如果没有配置 BusinessControl 对象为空
        Map<STRATEGY_CODE, BusinessControl> controlMap = this.checkGetBCMap(inputCods, enterpriseId, warehouseId, point,
          cargoOwnerId, bldgId);

        return strategyFactory.getStrategy(inputCods.get(0), point, controlMap);
    }

    public Map<STRATEGY_CODE, IStrategyHandle> selectHandleMap(List<STRATEGY_CODE> inputCods, String warehouseId,
                                                               String point) {
        UserDTO userDTO = userTemplate.getUserDTO();
        if (ObjectUtils.isNull(userDTO)) {
            throw new BizException("登入用户信息获取失败");
        }
        String enterpriseId = userDTO.getEnterpriseId();
        return this.selectHandleMap(inputCods, enterpriseId, warehouseId, point, null, null);
    }

    public Map<STRATEGY_CODE, IStrategyHandle> selectHandleMap(List<STRATEGY_CODE> inputCods, String enterpriseId,
                                                               String warehouseId, String point) {
        return this.selectHandleMap(inputCods, enterpriseId, warehouseId, point, null, null);
    }

    public Map<STRATEGY_CODE, IStrategyHandle> selectHandleMap(List<STRATEGY_CODE> inputCods, String enterpriseId,
                                                               String warehouseId, String point,
                                                               String cargoOwnerId) {
        return this.selectHandleMap(inputCods, enterpriseId, warehouseId, point, cargoOwnerId, null);
    }

    /**
     * 多配置返回所有配置对应的操作对象Map
     *
     * @param inputCods
     * @param enterpriseId
     * @param warehouseId
     * @param point
     * @param cargoOwnerId
     * @param bldgId
     * @return
     */
    public Map<STRATEGY_CODE, IStrategyHandle> selectHandleMap(List<STRATEGY_CODE> inputCods, String enterpriseId,
                                                               String warehouseId, String point, String cargoOwnerId,
                                                               String bldgId) {
        // 获取所有的业务配置参数内容，如果没有配置 BusinessControl 对象为空
        Map<STRATEGY_CODE, BusinessControl> controlMap = this.checkGetBCMap(inputCods, enterpriseId, warehouseId, point,
          cargoOwnerId, bldgId);

        return strategyFactory.getStrategy(point, controlMap);
    }

    /**
     * 检查必传参数
     *
     * @param inputCods
     * @param enterpriseId
     * @param warehouseId
     * @param point
     * @param cargoOwnerId
     * @param bldgId
     * @return
     */
    private Map<STRATEGY_CODE, BusinessControl> checkGetBCMap(List<STRATEGY_CODE> inputCods, String enterpriseId, String warehouseId,
                                                              String point, String cargoOwnerId, String bldgId) {
        if (ObjectUtils.isNull(inputCods)) {
            throw new ParameterException("配置参数列表不能为空");
        }
        if (StringUtils.isBlank(enterpriseId)) {
            UserDTO userDTO = userTemplate.getUserDTO();
            if (ObjectUtils.isNull(userDTO)) {
                throw new ParameterException("企业id不能为空");
            }
            enterpriseId = userDTO.getEnterpriseId();
        }
        if (StringUtils.isBlank(warehouseId)) {
            throw new ParameterException("仓库id不能为空");
        }

        // 获取所有的业务配置参数内容，如果没有配置 BusinessControl 对象为空
        return this.analysisStrategyInfo(inputCods, warehouseId, cargoOwnerId,
          enterpriseId, bldgId);
    }

    /**
     * 获取业务配置信息map
     * 如果备注内容中存在 data[数据]，会将 数据 提取出来替换为备注内容，以便后续业务功能使用
     * 数据内容会原封不动的拿出来，业务自行做加工处理
     * 如果没有配置 BusinessControl 对象为空
     *
     * @param inputCods
     * @param warehouseId
     * @param cargoOwnerId
     * @param enterpriseId
     * @param bldgId
     * @return
     */
    public Map<STRATEGY_CODE, BusinessControl> analysisStrategyInfo(List<STRATEGY_CODE> inputCods, String warehouseId,
                                                                    String cargoOwnerId, String enterpriseId, String bldgId) {
        List<String> regCodes = inputCods.stream().map(STRATEGY_CODE::getCode).collect(Collectors.toList());
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(
          regCodes.toArray(new String[regCodes.size()]), warehouseId, cargoOwnerId, enterpriseId, bldgId);
        if (!restMessage.isSuccess()) {
            throw new BizException("配置参数获取失败");
        }
        Map<String, BusinessControl> bCs = restMessage.getData();
        Map<STRATEGY_CODE, BusinessControl> resMap = new HashMap<>();
        // 备注中的数据分隔
        String dataStart = "data\\[";
        String dataEnd = "]";
        for (STRATEGY_CODE code : inputCods) {
            if (ObjectUtils.isNotNull(bCs) && bCs.containsKey(code.getCode())) {
                BusinessControl bC = bCs.get(code.getCode());
                String remark = ObjectUtils.isNull(bC) ? null : bC.getRemark();
                // 检查备注是否有data数据
                if (!StringUtils.isBlank(remark) && remark.contains(dataStart)) {
                    String dataS = remark.split(dataStart)[1];
                    // 随便加一个字符，防止 ] 结尾的情况
                    dataS += "a";
                    String[] dataEArr = dataS.split(dataEnd);
                    if (1 < dataEArr.length) {
                        // 数组长度大于1，分隔成功，获取值
                        String data = dataEArr[0];
                        // 将数据替换备注给后续使用
                        bC.setRemark(data);
                    }
                }
                resMap.put(code, bC);
            } else {
                resMap.put(code, null);
            }
        }

        return resMap;
    }
}
