package com.sckw.order.serivce;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.contract.api.model.dto.res.ContractLogisticsAndTradeOrderResDto;
import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.model.base.BaseModel;
import com.sckw.core.model.enums.AddressTypeEnum;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.model.vo.TableBottom;
import com.sckw.core.model.vo.TableStatisticRes;
import com.sckw.core.model.vo.TableTop;
import com.sckw.core.utils.BeanUtils;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.DateUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.result.PageDataResult;
import com.sckw.order.dao.KwoTradeOrderMapper;
import com.sckw.order.enums.OrderStatusEnum;
import com.sckw.order.enums.OrderUnitTypeEnum;
import com.sckw.order.model.*;
import com.sckw.order.model.dto.OrderListResDTO;
import com.sckw.order.model.dto.TradeOrderListSelectDTO;
import com.sckw.order.model.vo.req.*;
import com.sckw.order.model.vo.res.QueryTradeOrderResp;
import com.sckw.order.model.vo.res.TradeOrderDetailResp;
import com.sckw.order.repository.*;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.RemoteUserService;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.dubbo.TransportRemoteService;
import com.sckw.transport.api.model.vo.KwtLogisticsOrderVO;
import com.sckw.transport.api.model.vo.RTransportEntVo;
import com.sckw.transport.api.model.vo.RWaybillSubOrderVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @desc: 运营端贸易订单管理相关service
 * @author: yzc
 * @date: 2023-09-14 11:23
 */
@Service
@Slf4j
@AllArgsConstructor
public class TradeOrderManageService {

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteUserService remoteUserService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private GoodsInfoService goodsInfoService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TransportRemoteService transportRemoteService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteContractService remoteContractService;

    private final KwoTradeOrderService tradeOrderService;
    private final KwoTradeOrderMapper tradeOrderMapper;
    private final KwoTradeOrderGoodsRepository tradeOrderGoodsRepository;
    private final KwoTradeOrderRepository tradeOrderRepository;
    private final KwoTradeOrderAddressRepository tradeOrderAddressRepository;
    private final KwoTradeOrderUnitRepository tradeOrderUnitRepository;
    private final KwoTradeOrderContractRepository tradeOrderContractRepository;

    /**
     * @desc: 贸易订单列表分页查询
     * @author: yzc
     * @date: 2023-09-14 14:24
     * @Param params:
     * @return: com.sckw.core.model.page.PageResult
     */
    public PageResult listPaging(OperatorTOrderListQueryVO params) {
        TradeOrderListStatisticParam tradeOrderListStatisticParam = new TradeOrderListExportParam();
        BeanUtils.copyProperties(params, tradeOrderListStatisticParam);
        TradeOrderListSelectDTO tradeOrderListSelectDTO = tradeOrderService.buildSelectParam(tradeOrderListStatisticParam);
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<OrderListResDTO> list = tradeOrderMapper.tradeOrderSelect(tradeOrderListSelectDTO, tradeOrderListSelectDTO.getGoodIds(), LoginUserHolder.getAuthUserIdList(), null);
        return tradeOrderService.buildResult(list, params.getPageSize());
    }

    /**
     * @desc: 贸易订单列表统计查询
     * @author: yzc
     * @date: 2023-09-14 14:22
     * @Param params:
     * @return: com.sckw.core.model.vo.TableStatisticRes
     */
    public TableStatisticRes listStatistic(OperatorTOrderStsQueryVO params) {
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)) {
                List<OrderStatusEnum> enums = OrderStatusEnum.getSortList();
                enums.remove(0);
                List<TableTop> list = new ArrayList<>();
                for (OrderStatusEnum e : enums) {
                    Integer value = e.getCode();
                    TableTop tableTop = new TableTop();
                    tableTop.setName(e.getMsg()).setValue(value).setTotal(0);
                    list.add(tableTop);
                }
                TableTop all = new TableTop();
                all.setName("全部").setTotal(0);
                list.add(0, all);
                TableBottom tableBottom = new TableBottom();
                tableBottom.setTotal(0);
                TableStatisticRes res = new TableStatisticRes();
                res.setTableTops(list).setTableBottom(tableBottom);
                return res;
            }
            authEntIdList.addAll(ids);
        }
        List<OrderStatusEnum> enums = OrderStatusEnum.getSortList();
        enums.remove(0);
        return null;
    }

    /**
     * @desc: 贸易订单列表导出
     * @author: yzc
     * @date: 2023-09-14 14:40
     * @Param params:
     * @return: java.util.List<com.sckw.report.service.param.TradeOrderListExport>
     */
    public List<TradeOrderListExport> export(OperatorTOrderExportQueryVO params) {
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)) {
                List<TradeOrderListExport> exports = new ArrayList<>();
                return exports;
            }
            authEntIdList.addAll(ids);
        }
        return null;
    }

    /**
     * @desc: 合同关联订单列表
     * @author: yzc
     * @date: 2023-09-14 14:52
     * @Param params:
     * @return: com.sckw.core.model.page.PageResult
     */
    public PageResult contractAssociationList(OperatorTOrderContractParam params) {
        Criteria criteria = new Criteria();
        List<Long> ids = StringUtils.splitStrToList(params.getContractIds(), ",", Long.class);
        criteria.and("contractId").in(ids).and("delFlag").is(0);
        Sort sort = Sort.by(Sort.Direction.DESC, "contractId", "createTime");
        return null;
    }

    public PageDataResult<QueryTradeOrderResp> pageQueryTradeOrder(QueryTradeOrderReq req) {
        log.info("查询物流订单请求参数：{}", JSON.toJSONString( req));

        Set<Long> allEnt = getEnt(req);

        //查询商品信息
        List<Long> orderIds = getOrderIds(req);




        //分页查询订单
        IPage<KwoTradeOrder> page = tradeOrderRepository.queryByPage(allEnt,orderIds,req.getOrderNo(),
                req.getTradeOrderStatus(),
                req.getOrderStartTime(),
                req.getOrderEndTime(),
                req.getPageNum(),req.getPageSize());
        List<KwoTradeOrder> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }


        //贸易订单号
        Set<Long> tradeOrderIds = records.stream()
                .map(BaseModel::getId)
                .collect(Collectors.toSet());
        //获取创建人id
        List<Long> createByIds = records.stream()
                .map(BaseModel::getCreateBy).distinct()
                .collect(Collectors.toList());

        //查询用户信息
        Map<Long, UserCacheResDto> userIdAndUserMap = Maps.newHashMap() ;
        if (CollectionUtils.isNotEmpty(createByIds)){
            userIdAndUserMap = remoteSystemService.queryUserCacheMapByIds(createByIds);
        }

        //查询贸易合同商品信息
        Map<Long, KwoTradeOrderGoods> tradeOrderIdGoodsMap = Maps.newHashMap() ;
        List<KwoTradeOrderGoods> tradeOrderGoods = tradeOrderGoodsRepository.queryByOrderIds(tradeOrderIds);
        List<Long> goodsIdList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(tradeOrderGoods)){
            tradeOrderIdGoodsMap = tradeOrderGoods.stream()
                    .collect(Collectors.toMap(KwoTradeOrderGoods::getTOrderId, Function.identity(), (k, v) -> k));
            //获取商品id
            goodsIdList = tradeOrderGoods.stream()
                    .map(KwoTradeOrderGoods::getGoodsId)
                    .distinct()
                    .collect(Collectors.toList());
        }

        //查询商品信息
        Map<Long, KwpGoods> goodsIdAndGoodsMap = getLongKwpGoodsMap(goodsIdList);

        //查询贸易订单公司信息
        Map<String, KwoTradeOrderUnit> orderIdUnitTypeAndUnitMap = getStringKwoTradeOrderUnitMap(tradeOrderIds);
        //查询贸易订单地址信息
        Map<String, KwoTradeOrderAddress> orderIdAndAddressMap = getStringKwoTradeOrderAddressMap(tradeOrderIds);
        //查询贸易订单合同信息(一个贸易合同对应多个贸易订单)
        Map<Long, KwoTradeOrderContract> tradeOrderIdAndContractMap = getLongKwoTradeOrderContractMap(tradeOrderIds);

        //查询物流信息
        Map<Integer, RTransportEntVo> entTypeAndTransportEntMap = getIntegerRTransportEntVoMap(tradeOrderIds);
        //查询运单信息
        Map<Long, RWaybillSubOrderVo> tradeIdAndSubOrderVoMap = getLongRWaybillSubOrderVoMap(tradeOrderIds);

        Map<Long, KwoTradeOrderGoods> finalTradeOrderIdGoodsMap = tradeOrderIdGoodsMap;
        Map<Long, UserCacheResDto> finalUserIdAndUserMap = userIdAndUserMap;
        //组装返回参数
        List<QueryTradeOrderResp> results = records.stream()
                .map(tradeOrder -> getQueryTradeOrderResp(tradeOrder, orderIdUnitTypeAndUnitMap, entTypeAndTransportEntMap, finalTradeOrderIdGoodsMap, goodsIdAndGoodsMap, tradeIdAndSubOrderVoMap
                        , orderIdAndAddressMap, tradeOrderIdAndContractMap, finalUserIdAndUserMap))
                .collect(Collectors.toList());
        return PageDataResult.of(page, results);
    }

    @NotNull
    private Set<Long> getEnt(QueryTradeOrderReq req) {
        Set<Long> allEnt = Sets.newHashSet();
        //根据企业类型查询企业
        if(StringUtils.isNotBlank(req.getEntId())){
            allEnt.add(Long.parseLong(req.getEntId()));
            EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(Long.parseLong(req.getEntId()));
            if (Objects.nonNull(entCacheResDto)) {
                EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntTreeById(entCacheResDto.getId());
                List<EntCacheResDto> child = entCacheResDto1.getChild();
                if (CollectionUtils.isNotEmpty(child)) {
                    allEnt.addAll(child.stream().filter(x->x.getEntTypes().contains(req.getEntType())).map(EntCacheResDto::getId).toList());
                }
            }
        }
        return allEnt;
    }

    @NotNull
    private List<Long> getOrderIds(QueryTradeOrderReq req) {
        List<KwpGoods> kwpGoodsList = Lists.newArrayList();
        if (!org.apache.commons.lang3.StringUtils.isAllBlank(req.getGoodsName(), req.getGoodsType(),
                req.getGoodsSpec())){
            kwpGoodsList = goodsInfoService.getGoodsByNameTypeDesc(req.getGoodsName(), req.getGoodsType(),
                    req.getGoodsSpec());

        }
        Set<Long> goodsIds = Sets.newHashSet();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwpGoodsList)){
            goodsIds = kwpGoodsList.stream().map(KwpGoods::getId).collect(Collectors.toSet());
        }


        //根据商品信息查询物流订单商品
        List<KwoTradeOrderGoods> kwoTradeOrderGoodsList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(goodsIds)){
            kwoTradeOrderGoodsList =
                    tradeOrderGoodsRepository.queryByGoodsIds(goodsIds);
        }
        List<Long> orderIds = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(kwoTradeOrderGoodsList)){
            orderIds.addAll(kwoTradeOrderGoodsList.stream()
                    .map(KwoTradeOrderGoods::getTOrderId)
                    .toList());
        }


        if (StringUtils.isNotBlank(req.getTradeOrderId())){
            orderIds.add(Long.valueOf(req.getTradeOrderId()));
        }
        List<Object> entIds = Lists.newArrayList();
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getSupplyEntId())){
            entIds.add(Long.valueOf(req.getSupplyEntId()));
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getPurchaseEntId())){
            entIds.add(Long.valueOf(req.getPurchaseEntId()));
        }

        //查询供应企业
        List<KwoTradeOrderUnit> kwoTradeOrderUnits = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(entIds)){
            kwoTradeOrderUnits = tradeOrderUnitRepository.queryByEntIds(entIds);
        }

        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwoTradeOrderUnits)){
            orderIds.addAll(kwoTradeOrderUnits.stream()
                    .map(KwoTradeOrderUnit::getTOrderId)
                    .collect(Collectors.toSet()));
        }
        //查询承运单位
        if (StringUtils.isNotBlank(req.getCarriageEntId())){
            List<KwtLogisticsOrderVO> kwtLogisticsOrderVOS = transportRemoteService.queryTransportEntByEntId(Long.parseLong(req.getCarriageEntId()));
            if (CollectionUtils.isNotEmpty(kwtLogisticsOrderVOS)){
                orderIds.addAll(kwtLogisticsOrderVOS.stream()
                        .map(KwtLogisticsOrderVO::getTOrderId)
                        .collect(Collectors.toSet()));
            }
        }
        return orderIds;
    }

    private Map<Long, KwpGoods> getLongKwpGoodsMap(List<Long> goodsIdList) {
        Map<Long, KwpGoods> goodsIdAndGoodsMap = Maps.newHashMap() ;
        if (CollectionUtils.isNotEmpty(goodsIdList)){
           goodsIdAndGoodsMap = goodsInfoService.getGoodsByIds(goodsIdList);
        }
        return goodsIdAndGoodsMap;
    }

    @NotNull
    private Map<String, KwoTradeOrderUnit> getStringKwoTradeOrderUnitMap(Set<Long> tradeOrderIds) {
        List<KwoTradeOrderUnit> tradeOrderUnits = tradeOrderUnitRepository.queryByOrderIds(tradeOrderIds);
        Map<String, KwoTradeOrderUnit> orderIdUnitTypeAndUnitMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tradeOrderUnits)){
            //按照订单号类型进行映射
            orderIdUnitTypeAndUnitMap = tradeOrderUnits.stream()
                    .peek(x -> x.setTradeOrderIdAndUnitType(x.getTOrderNo() + "-" + x.getUnitType()))
                    .collect(Collectors.toMap(KwoTradeOrderUnit::getTradeOrderIdAndUnitType, Function.identity(), (k,
                                                                                                                   v) -> k));
        }
        return orderIdUnitTypeAndUnitMap;
    }

    @NotNull
    private Map<String, KwoTradeOrderAddress> getStringKwoTradeOrderAddressMap(Set<Long> tradeOrderIds) {
        List<KwoTradeOrderAddress> tradeOrderAddresses = tradeOrderAddressRepository.queryByOrderIds(tradeOrderIds);
        Map<String, KwoTradeOrderAddress> orderIdAndAddressMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tradeOrderAddresses)){
            //将贸易订单id和地址类型组成key映射地址信息
            orderIdAndAddressMap = tradeOrderAddresses.stream()
                    .peek(x -> x.setTradeOrderIdTypeKey(x.getTOrderId() + "-" + x.getAddressType()))
                    .collect(Collectors.toMap(KwoTradeOrderAddress::getTradeOrderIdTypeKey,Function.identity(),
                            (k, v)->k));
         }
        return orderIdAndAddressMap;
    }

    @NotNull
    private Map<Long, KwoTradeOrderContract> getLongKwoTradeOrderContractMap(Set<Long> tradeOrderIds) {
        List<KwoTradeOrderContract> tradeOrderContracts = tradeOrderContractRepository.queryByOrderIds(tradeOrderIds);
        Map<Long, KwoTradeOrderContract> tradeOrderIdAndContractMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(tradeOrderContracts)){
            tradeOrderIdAndContractMap = tradeOrderContracts.stream()
                    .collect(Collectors.toMap(KwoTradeOrderContract::getTOrderId,
                    Function.identity(), (k1, k2) -> k1));
        }
        return tradeOrderIdAndContractMap;
    }

    @NotNull
    private Map<Integer, RTransportEntVo> getIntegerRTransportEntVoMap(Set<Long> tradeOrderIds) {
        List<RTransportEntVo> transportEnts = transportRemoteService.queryTransportEnt(tradeOrderIds);
        Map<Integer, RTransportEntVo> entTypeAndTransportEntMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(transportEnts)){
            entTypeAndTransportEntMap =
                    transportEnts.stream().collect(Collectors.toMap(RTransportEntVo::getTransportEntType, Function.identity(),
                    (k, v) -> k));
        }
        return entTypeAndTransportEntMap;
    }

    @NotNull
    private Map<Long, RWaybillSubOrderVo> getLongRWaybillSubOrderVoMap(Set<Long> tradeOrderIds) {
        List<RWaybillSubOrderVo> subOrderVoList = transportRemoteService.queryWaybillOrderByTradeOrderIds(tradeOrderIds);
        Map<Long, RWaybillSubOrderVo> tradeIdAndSubOrderVoMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(subOrderVoList)){
            tradeIdAndSubOrderVoMap = subOrderVoList.stream()
                    .collect(Collectors.toMap(RWaybillSubOrderVo::getTradeId, Function.identity(), (k, v) -> k));
        }
        return tradeIdAndSubOrderVoMap;
    }

    @NotNull
    private static QueryTradeOrderResp getQueryTradeOrderResp(KwoTradeOrder tradeOrder, Map<String, KwoTradeOrderUnit> finalOrderIdUnitTypeAndUnitMap, Map<Integer, RTransportEntVo> finalEntTypeAndTransportEntMap, Map<Long, KwoTradeOrderGoods> finalTradeOrderIdGoodsMap, Map<Long, KwpGoods> finalGoodsIdAndGoodsMap, Map<Long, RWaybillSubOrderVo> finalTradeIdAndSubOrderVoMap, Map<String, KwoTradeOrderAddress> finalOrderIdAndAddressMap, Map<Long, KwoTradeOrderContract> finalTradeOrderIdAndContractMap, Map<Long, UserCacheResDto> finalUserIdAndUserMap) {
        QueryTradeOrderResp queryTradeOrderResp = new QueryTradeOrderResp();
        queryTradeOrderResp.setOrderId(String.valueOf(tradeOrder.getId()));
        queryTradeOrderResp.setOrderNo(tradeOrder.getTOrderNo());
        KwoTradeOrderUnit purchaseEnt = finalOrderIdUnitTypeAndUnitMap.getOrDefault(tradeOrder.getId() + "-" + OrderUnitTypeEnum.PURCHASE.getType(),
                new KwoTradeOrderUnit());

        queryTradeOrderResp.setPurchaseEntId(String.valueOf(purchaseEnt.getEntId()));
        queryTradeOrderResp.setPurchaseFirmName(purchaseEnt.getFirmName());
        KwoTradeOrderUnit supplyEnt =
                finalOrderIdUnitTypeAndUnitMap.getOrDefault(tradeOrder.getId() + "-" + OrderUnitTypeEnum.SALE.getType(),
                        new KwoTradeOrderUnit());
        queryTradeOrderResp.setSupplyEntId(String.valueOf(supplyEnt.getEntId()));
        queryTradeOrderResp.setSupplyFirmName(supplyEnt.getFirmName());
        //1.承运 2.拖运
        RTransportEntVo transportEntVo = finalEntTypeAndTransportEntMap.getOrDefault(2, new RTransportEntVo());
        queryTradeOrderResp.setTransportEntId(String.valueOf(transportEntVo.getTransportEntId()));
        queryTradeOrderResp.setTransportFirmName(transportEntVo.getTransportEntName());

        KwoTradeOrderGoods tradeOrderGood = finalTradeOrderIdGoodsMap.getOrDefault(tradeOrder.getId(), new KwoTradeOrderGoods());
        KwpGoods kwpGoods = finalGoodsIdAndGoodsMap.getOrDefault(tradeOrderGood.getGoodsId(), new KwpGoods());
        queryTradeOrderResp.setGoodsName(kwpGoods.getName() + "/" + kwpGoods.getGoodsType() + "/" + kwpGoods.getSpec());
        queryTradeOrderResp.setGoodsPrice(Objects.nonNull(tradeOrderGood.getUnitPrice()) ?
                tradeOrderGood.getUnitPrice().setScale(2, RoundingMode.HALF_UP).toPlainString() : "");
        queryTradeOrderResp.setChargeType(String.valueOf(tradeOrder.getChargeType()));
        queryTradeOrderResp.setChargeType(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(),
                String.valueOf(tradeOrder.getChargeType())));


        RWaybillSubOrderVo subOrderVo = finalTradeIdAndSubOrderVoMap.getOrDefault(tradeOrder.getId(),
                new RWaybillSubOrderVo());
        List<RWaybillSubOrderVo.BillSubOrder> subOrders = subOrderVo.getSubOrders();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(subOrders)) {
            BigDecimal sum = subOrders.stream()
                    .map(RWaybillSubOrderVo.BillSubOrder::getLoadAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal unloadQty = subOrders.stream()
                    .map(RWaybillSubOrderVo.BillSubOrder::getUnloadAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            queryTradeOrderResp.setLoadQty(sum.setScale(2, RoundingMode.HALF_UP).toPlainString());
            queryTradeOrderResp.setUnloadQty(unloadQty.setScale(2, RoundingMode.HALF_UP).toPlainString());
        }
        queryTradeOrderResp.setOrderQty(Objects.nonNull(tradeOrder.getAmount()) ?
                tradeOrder.getAmount().setScale(2, RoundingMode.HALF_UP).toPlainString() : "");
        KwoTradeOrderAddress loadAdd = finalOrderIdAndAddressMap.getOrDefault(tradeOrder.getId() + "-" + AddressTypeEnum.SHIPMENT.getCode(),
                new KwoTradeOrderAddress());
        queryTradeOrderResp.setLoadAddress(loadAdd.getDetailAddress());

        KwoTradeOrderAddress unLoadAdd =
                finalOrderIdAndAddressMap.getOrDefault(tradeOrder.getId() + "-" + AddressTypeEnum.TAKE.getCode(),
                        new KwoTradeOrderAddress());
        queryTradeOrderResp.setUnloadAddress(unLoadAdd.getDetailAddress());
        queryTradeOrderResp.setUnloadContacts(unLoadAdd.getContacts());
        queryTradeOrderResp.setUnloadPhone(unLoadAdd.getPhone());
        queryTradeOrderResp.setStartTime(DateUtils.format(tradeOrder.getStartTime(), DateUtils.DATE_PATTERN));
        queryTradeOrderResp.setEndTime(DateUtils.format(tradeOrder.getEndTime(), DateUtils.DATE_PATTERN));
        KwoTradeOrderContract orderContract = finalTradeOrderIdAndContractMap.getOrDefault(tradeOrder.getId(),
                new KwoTradeOrderContract());
        queryTradeOrderResp.setContractNo(orderContract.getContractNo());
        UserCacheResDto userCacheResDto = finalUserIdAndUserMap.getOrDefault(tradeOrder.getCreateBy(), new UserCacheResDto());
        queryTradeOrderResp.setCreateUser(userCacheResDto.getName());
        queryTradeOrderResp.setCreateTime(DateUtils.format(tradeOrder.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
        return queryTradeOrderResp;
    }

    public TradeOrderDetailResp getTradeOrderDetail(TradeOrderDetailReq req) {
        log.info("贸易订单详情查询请求参数req:{}", JSON.toJSONString(req));
        KwoTradeOrder tradeOrder = tradeOrderRepository.queryByTradeOrderId(Long.valueOf(req.getTradeOrderId()));
        if (Objects.isNull(tradeOrder)){
            throw new BusinessException("贸易订单不存在");
        }
        //根据贸易id查询贸易合同信息
        KwoTradeOrderContract tradeOrderContract = tradeOrderContractRepository.queryByTradeOrderId(tradeOrder.getId());
        //获取合同id
        Long tradeOrderContractId =
                Optional.ofNullable(tradeOrderContract).map(KwoTradeOrderContract::getTOrderId).orElse(null);
        //查询合同信息
        ContractLogisticsAndTradeOrderResDto logisticsAndTradeOrder = remoteContractService.queryContractByContractId(tradeOrderContractId
                , tradeOrder.getId());

        //查询贸易订单相关的贸易企业信息
        List<KwoTradeOrderUnit> kwoTradeOrderUnits = tradeOrderUnitRepository.queryByOrderId(tradeOrder.getId());
        Map<String, KwoTradeOrderUnit> tradeOrderIdAndUnitTypeAndUnitMap = Maps.newHashMap() ;
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwoTradeOrderUnits)){
           tradeOrderIdAndUnitTypeAndUnitMap = kwoTradeOrderUnits.stream()
                    .peek(x -> x.setTradeOrderIdAndUnitType(tradeOrder.getId() + "-" + x.getUnitType()))
                    .collect(Collectors.toMap(KwoTradeOrderUnit::getTradeOrderIdAndUnitType, Function.identity(), (x, y) -> x));
        }
        //查询承运单位
        List<RTransportEntVo> logisticsEnts = transportRemoteService.queryTransportEntByTradeOrderId(tradeOrder.getId());
        //查询物流订单
        List<KwtLogisticsOrderVO> kwtLogisticsOrderVOS = transportRemoteService.queryLogisticOrderByTradeId(tradeOrder.getId());
        //物流订单id映射物流信息
        Map<Long, KwtLogisticsOrderVO> logIdAndLogisticsOrderMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwtLogisticsOrderVOS)){
            logIdAndLogisticsOrderMap = kwtLogisticsOrderVOS.stream()
                    .collect(Collectors.toMap(KwtLogisticsOrderVO::getId, Function.identity(), (x, y) -> x));
        }
        //根据物流订单查询运单
        List<RWaybillSubOrderVo> rWaybillSubOrderVos = transportRemoteService.queryWaybillOrderByTradeOrderIds(Set.of(tradeOrder.getId()));
        //将贸易订单id和运单进行映射
        Map<Long, RWaybillSubOrderVo> tradeOrderIdAndSubOrderVoMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(rWaybillSubOrderVos)){
            tradeOrderIdAndSubOrderVoMap = rWaybillSubOrderVos.stream().collect(Collectors.toMap(RWaybillSubOrderVo::getTradeId, Function.identity()
                    , (k1, k2) -> k1));
        }

        //查询贸易订单商品信息
        KwoTradeOrderGoods tradeOrderGoods = tradeOrderGoodsRepository.queryByOrderId(tradeOrder.getId());
        Long goodsId = Optional.ofNullable(tradeOrderGoods)
                .map(KwoTradeOrderGoods::getGoodsId)
                .orElse(null);
        //更具商品id查询商品信息
        KwpGoods goods = goodsInfoService.getGoodsById(goodsId);

        //获取贸易订单地址
        List<KwoTradeOrderAddress> tradeOrderAddresses = tradeOrderAddressRepository.queryByOrderId(tradeOrder.getId());
        Map<String, KwoTradeOrderAddress> tradeOrderIdAndAddressMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tradeOrderAddresses)){
            tradeOrderIdAndAddressMap = tradeOrderAddresses.stream()
                    .peek(x -> x.setTradeOrderIdTypeKey(tradeOrder.getId() + "-" + x.getAddressType()))
                    .collect(Collectors.toMap(KwoTradeOrderAddress::getTradeOrderIdTypeKey, Function.identity(), (x, y) -> x));
        }

        //组装明细信息
        return getTradeOrderDetailResp(tradeOrder, logisticsAndTradeOrder, tradeOrderIdAndUnitTypeAndUnitMap, logisticsEnts, kwtLogisticsOrderVOS, goods, tradeOrderIdAndAddressMap, tradeOrderIdAndSubOrderVoMap, logIdAndLogisticsOrderMap);
    }

    @NotNull
    private static TradeOrderDetailResp getTradeOrderDetailResp(KwoTradeOrder tradeOrder, ContractLogisticsAndTradeOrderResDto logisticsAndTradeOrder, Map<String, KwoTradeOrderUnit> tradeOrderIdAndUnitTypeAndUnitMap, List<RTransportEntVo> logisticsEnts, List<KwtLogisticsOrderVO> kwtLogisticsOrderVOS, KwpGoods goods, Map<String, KwoTradeOrderAddress> tradeOrderIdAndAddressMap, Map<Long, RWaybillSubOrderVo> tradeOrderIdAndSubOrderVoMap, Map<Long, KwtLogisticsOrderVO> logIdAndLogisticsOrderMap) {
        TradeOrderDetailResp tradeOrderDetailResp = new TradeOrderDetailResp();
        //合同信息
        setContractInfo(tradeOrderDetailResp, tradeOrder, logisticsAndTradeOrder);

        //单位信息列表
        setTradeOrderUnitInfo(tradeOrderIdAndUnitTypeAndUnitMap, tradeOrder, logisticsEnts, kwtLogisticsOrderVOS, tradeOrderDetailResp);

        //商品信息
        setGoodsInfo(goods, tradeOrder, tradeOrderDetailResp);

        //卸货信息
        setUnloadInfo(tradeOrderIdAndAddressMap, tradeOrder, tradeOrderDetailResp);
        //履约信息
        setPerform(tradeOrder, tradeOrderIdAndSubOrderVoMap, logIdAndLogisticsOrderMap, tradeOrderDetailResp);
        tradeOrderDetailResp.setRemark(tradeOrder.getRemark());
        return tradeOrderDetailResp;
    }

    private static void setPerform(KwoTradeOrder tradeOrder, Map<Long, RWaybillSubOrderVo> tradeOrderIdAndSubOrderVoMap, Map<Long, KwtLogisticsOrderVO> logIdAndLogisticsOrderMap, TradeOrderDetailResp tradeOrderDetailResp) {
        TradeOrderDetailResp.TradeOrderPerformanceInfo tradeOrderPerformanceInfo = new TradeOrderDetailResp.TradeOrderPerformanceInfo();
        tradeOrderPerformanceInfo.setPayType(String.valueOf(tradeOrder.getTrading()));
        tradeOrderPerformanceInfo.setPayTypeDesc(DictEnum.getLabel(DictTypeEnum.TRADE_TYPE.getType(),
                tradeOrder.getTrading()));
        tradeOrderPerformanceInfo.setTransportType(String.valueOf(tradeOrder.getConsignmentWay()));
        tradeOrderPerformanceInfo.setTransportTypeDesc(DictEnum.getLabel(DictTypeEnum.CONSIGNMENT_WAY.getType(),
                String.valueOf(tradeOrder.getConsignmentWay())));
        tradeOrderPerformanceInfo.setPriceType(String.valueOf(tradeOrder.getChargeType()));
        tradeOrderPerformanceInfo.setPriceTypeDesc(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(),
                String.valueOf(tradeOrder.getChargeType())));
        RWaybillSubOrderVo rWaybillSubOrderVo = tradeOrderIdAndSubOrderVoMap.getOrDefault(tradeOrder.getId(),new RWaybillSubOrderVo());
        List<RWaybillSubOrderVo.BillSubOrder> subOrders = rWaybillSubOrderVo.getSubOrders();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(subOrders)){

            //累计装货量
            BigDecimal loadTotal = subOrders.stream()
                    .map(RWaybillSubOrderVo.BillSubOrder::getLoadAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal unloadTotal = subOrders.stream()
                    .map(RWaybillSubOrderVo.BillSubOrder::getUnloadAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal loadAmount = BigDecimal.ZERO ;
            if (org.apache.commons.lang3.StringUtils.equals(String.valueOf(tradeOrder.getTrading()),
                    DictEnum.CHARGING_TYPE_2.getValue())){
                //已履约量
                loadAmount = subOrders.stream()
                        .map(RWaybillSubOrderVo.BillSubOrder::getUnloadAmount)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
            }else if (org.apache.commons.lang3.StringUtils.equals(String.valueOf(tradeOrder.getTrading()),
                    DictEnum.CHARGING_TYPE_1.getValue())){
                //已履约量
                loadAmount = subOrders.stream()
                        .map(RWaybillSubOrderVo.BillSubOrder::getLoadAmount)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

            }
            tradeOrderPerformanceInfo.setLoadAmount(loadAmount.setScale(2, RoundingMode.HALF_UP).toPlainString());

            tradeOrderPerformanceInfo.setLoadTotal(loadTotal.setScale(2, RoundingMode.HALF_UP).toPlainString());

            tradeOrderPerformanceInfo.setUnloadTotal(unloadTotal.setScale(2, RoundingMode.HALF_UP).toPlainString());
            //按照物流id进行分组
            Map<Long, List<RWaybillSubOrderVo.BillSubOrder>> logIdAndSubOrderVoMap =
                    subOrders.stream().collect(Collectors.groupingBy(RWaybillSubOrderVo.BillSubOrder::getLOrderId));
            Map<Long, KwtLogisticsOrderVO> finalLogIdAndLogisticsOrderMap = logIdAndLogisticsOrderMap;
            logIdAndSubOrderVoMap.forEach((logId, subOrderVos) -> {
                KwtLogisticsOrderVO logisticsOrder = finalLogIdAndLogisticsOrderMap.getOrDefault(logId, new KwtLogisticsOrderVO());
                BigDecimal price =
                        Optional.ofNullable(logisticsOrder).map(KwtLogisticsOrderVO::getPrice).orElse(BigDecimal.ZERO);
                BigDecimal sum = BigDecimal.ZERO ;
                if (org.apache.commons.lang3.StringUtils.equals(String.valueOf(tradeOrder.getTrading()),
                        DictEnum.CHARGING_TYPE_2.getValue())){
                    //已履约量
                    sum = subOrderVos.stream()
                            .map(RWaybillSubOrderVo.BillSubOrder::getUnloadAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                }else if (org.apache.commons.lang3.StringUtils.equals(String.valueOf(tradeOrder.getTrading()),
                        DictEnum.CHARGING_TYPE_1.getValue())){
                    //已履约量
                    sum = subOrderVos.stream()
                            .map(RWaybillSubOrderVo.BillSubOrder::getLoadAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);

                }
             tradeOrderPerformanceInfo.setLoadAmountPrice(price.multiply(sum).setScale(2,
                     RoundingMode.HALF_UP).toPlainString());
            });
        }

        tradeOrderDetailResp.setTradeOrderPerformanceInfo(tradeOrderPerformanceInfo);
    }

    private static void setUnloadInfo(Map<String, KwoTradeOrderAddress> tradeOrderIdAndAddressMap, KwoTradeOrder tradeOrder, TradeOrderDetailResp tradeOrderDetailResp) {
        TradeOrderDetailResp.TradeOrderUnloadInfo tradeOrderUnloadInfo = new TradeOrderDetailResp.TradeOrderUnloadInfo();
        KwoTradeOrderAddress unloadAdd = tradeOrderIdAndAddressMap.getOrDefault(tradeOrder.getId() + "-" + AddressTypeEnum.TAKE.getCode(),
                new KwoTradeOrderAddress());
        tradeOrderUnloadInfo.setUnloadAddress(unloadAdd.getDetailAddress());
        tradeOrderUnloadInfo.setUnloadContacts(unloadAdd.getContacts());
        tradeOrderUnloadInfo.setUnloadContactsPhone(unloadAdd.getPhone());
        tradeOrderDetailResp.setTradeOrderUnloadInfo(tradeOrderUnloadInfo);
    }

    private static void setGoodsInfo(KwpGoods goods, KwoTradeOrder tradeOrder, TradeOrderDetailResp tradeOrderDetailResp) {
        TradeOrderDetailResp.TradeOrderGoodsInfo tradeOrderGoodsInfo = new TradeOrderDetailResp.TradeOrderGoodsInfo();
        if (Objects.nonNull(goods)){
            tradeOrderGoodsInfo.setGoodsId(String.valueOf(goods.getId()));
            tradeOrderGoodsInfo.setGoodsName(goods.getName());
        }
        tradeOrderGoodsInfo.setUnitPrice(Objects.nonNull(tradeOrder.getPrice()) ? tradeOrder.getPrice().toPlainString() : null);
        tradeOrderGoodsInfo.setOrderTotal(Objects.nonNull(tradeOrder.getAmount()) ? tradeOrder.getAmount().toPlainString() : null);
        if (Objects.nonNull(tradeOrder.getPrice()) && Objects.nonNull(tradeOrder.getAmount())){
            tradeOrderGoodsInfo.setOrderAmount(tradeOrder.getAmount().multiply(tradeOrder.getAmount()).setScale(2
                    , RoundingMode.HALF_UP).toPlainString());
        }
        tradeOrderDetailResp.setTradeOrderGoodsInfo(tradeOrderGoodsInfo);
    }

    private static void setTradeOrderUnitInfo(Map<String, KwoTradeOrderUnit> tradeOrderIdAndUnitTypeAndUnitMap, KwoTradeOrder tradeOrder, List<RTransportEntVo> logisticsEnts, List<KwtLogisticsOrderVO> kwtLogisticsOrderVOS, TradeOrderDetailResp tradeOrderDetailResp) {
        TradeOrderDetailResp.TradeOrderUnitInfo tradeOrderUnitInfo = new TradeOrderDetailResp.TradeOrderUnitInfo();
        KwoTradeOrderUnit purchaseUnit = tradeOrderIdAndUnitTypeAndUnitMap.getOrDefault(tradeOrder.getId() + "-" + OrderUnitTypeEnum.PURCHASE.getType(),
                new KwoTradeOrderUnit());
        tradeOrderUnitInfo.setPurchaseUnitId(String.valueOf(purchaseUnit.getId()));
        tradeOrderUnitInfo.setPurchaseUnitName(purchaseUnit.getFirmName());
        tradeOrderUnitInfo.setPurchaseContacts(purchaseUnit.getContacts());
        tradeOrderUnitInfo.setPurchaseContactsPhone(purchaseUnit.getPhone());
        KwoTradeOrderUnit supplyUnit =
                tradeOrderIdAndUnitTypeAndUnitMap.getOrDefault(tradeOrder.getId() + "-" + OrderUnitTypeEnum.SALE.getType(),
                new KwoTradeOrderUnit());
        tradeOrderUnitInfo.setSupplyUnitId(String.valueOf(supplyUnit.getId()));
        tradeOrderUnitInfo.setSupplyUnitName(supplyUnit.getFirmName());
        tradeOrderUnitInfo.setSupplyContacts(supplyUnit.getContacts());
        tradeOrderUnitInfo.setSupplyContactsPhone(supplyUnit.getPhone());
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(logisticsEnts)){
            logisticsEnts.forEach(l->{
                tradeOrderUnitInfo.setCarriageUnitId(String.valueOf(l.getTransportEntId()));
                tradeOrderUnitInfo.setCarriageUnitName(l.getTransportEntName());
                tradeOrderUnitInfo.setCarriageContacts(l.getTransportContacts());
                tradeOrderUnitInfo.setCarriageContactsPhone(l.getTransportContactsPhone());
                tradeOrderUnitInfo.setCarriagePrice(Objects.nonNull(l.getTransportPrice())?
                        l.getTransportPrice().setScale(2, RoundingMode.HALF_UP).toPlainString():
                        null);
            });
        }

        BigDecimal carriageCost = BigDecimal.ZERO;
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwtLogisticsOrderVOS)){
            carriageCost = kwtLogisticsOrderVOS.stream()
                    .map(order -> {
                        BigDecimal price = order.getPrice() != null ? order.getPrice() : BigDecimal.ZERO;
                        BigDecimal amount = order.getAmount() != null ? order.getAmount() : BigDecimal.ZERO;
                        return price.multiply(amount);
                    })
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

        }
        tradeOrderUnitInfo.setCarriageCost(carriageCost.setScale(2, RoundingMode.HALF_UP).toPlainString());
        tradeOrderDetailResp.setTradeOrderUnitInfo(tradeOrderUnitInfo);
    }

    private static void setContractInfo(TradeOrderDetailResp tradeOrderDetailResp, KwoTradeOrder tradeOrder, ContractLogisticsAndTradeOrderResDto logisticsAndTradeOrder) {
        tradeOrderDetailResp.setTradeOrderId(String.valueOf(tradeOrder.getId()));
        TradeOrderDetailResp.TradeOrderContractInfo tradeOrderContractInfo = new TradeOrderDetailResp.TradeOrderContractInfo();
        tradeOrderContractInfo.setContractName(logisticsAndTradeOrder.getContactName());
        tradeOrderContractInfo.setContractNo(logisticsAndTradeOrder.getContractNo());
        List<ContractLogisticsAndTradeOrderResDto.ContractLogisticsOrder> logisticsContracts = logisticsAndTradeOrder.getLogisticsContracts();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(logisticsContracts)){
            List<TradeOrderDetailResp.LogisticsContract> logisticsContractList =
                    logisticsContracts.stream().map(logisticsContract -> {
                TradeOrderDetailResp.LogisticsContract logisticsContract1 = new TradeOrderDetailResp.LogisticsContract();
                logisticsContract1.setLogisticsContractName(logisticsContract.getLogisticsContractName());
                logisticsContract1.setLogisticsContractNo(logisticsContract.getLogisticsContractNo());
                return logisticsContract1;
            }).collect(Collectors.toList());
            tradeOrderContractInfo.setLogisticsContracts(logisticsContractList);
        }
        tradeOrderDetailResp.setTradeOrderContractInfo(tradeOrderContractInfo);
    }
}
