package com.sckw.order.serivce;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.contract.api.model.dto.res.ContractCommonInfoResDto;
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.constant.Global;
import com.sckw.core.utils.BeanUtils;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.OrderGenerateUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.mongo.model.SckwTradeOrder;
import com.sckw.order.dao.KwoTradeOrderMapper;
import com.sckw.order.model.*;
import com.sckw.order.model.dto.OrderCheckDTO;
import com.sckw.order.model.vo.req.*;
import com.sckw.order.model.vo.res.*;
import com.sckw.payment.api.dubbo.PayCenterDubboService;
import com.sckw.payment.api.model.constant.ChannelEnum;
import com.sckw.payment.api.model.dto.WalletDto;
import com.sckw.payment.api.model.dto.common.R;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.GoodsDetail;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.stream.model.SckwBusSum;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.AreaTreeFrontResDto;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.dubbo.TransportDubboService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @desc: 交易订单（采购订单/销售订单）service
 * @author: yzc
 * @date: 2023-06-25 14:28
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class KwoTradeOrderService {

    @DubboReference(version = "2.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;

    @DubboReference(version = "2.0.0", group = "design", check = false)
    private GoodsInfoService goodsInfoService;

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

    @DubboReference(version = "2.0.0", group = "design", check = false)
    private PayCenterDubboService payCenterDubboService;

    @DubboReference(version = "2.0.0", group = "design", check = false)
    private TransportDubboService transportDubboService;

    private final KwoTradeOrderMapper kwoTradeOrderMapper;
    private final StreamBridge streamBridge;
    private final KwoTradeOrderAddressService kwoTradeOrderAddressService;
    private final KwoTradeOrderUnitService kwoTradeOrderUnitService;
    private final KwoTradeOrderGoodsService kwoTradeOrderGoodsService;
    private final KwoTradeOrderContractService kwoTradeOrderContractService;
    private final KwoTradeOrderTrackService kwoTradeOrderTrackService;

    private static final String ORDER_NO_PREFIX = "CD";

    /**
     * @desc: 采购下单草稿
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addPurchaseOrderDraft(PurchaseOrderDraftParam param) {
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(OrderGenerateUtils.generateOrderNo(ORDER_NO_PREFIX))
                .setUnit(Objects.nonNull(param.getGoodsInfo()) ? param.getGoodsInfo().getUnit() : null)
                .setSource(DictEnum.TORDER_SOURCE_1.getValue()).setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_0.getValue()));
        kwoTradeOrderMapper.insert(order);
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);

    }

    /**
     * @desc: 添加其他订单信息
     * @author: yzc
     * @date: 2023-07-13 8:53
     * @Param tradeOrder:
     * @Param param:
     * @Param isUpdate:
     * @return: void
     */
    private void addOtherOrderInfo(KwoTradeOrder tradeOrder, ValetOrderParam param, Boolean isUpdate) {
        Long id = tradeOrder.getId();
        String tOrderNo = tradeOrder.getTOrderNo();
        SckwTradeOrder order = new SckwTradeOrder();
        order.setFirmName(LoginUserHolder.getEntName()).setTOrderId(id).setCreateByName(LoginUserHolder.getUserName())
                .setUpdateByName(LoginUserHolder.getUserName()).setAssociateStatement(0);
        BeanUtils.copyProperties(tradeOrder, order);
        //商品信息
        kwoTradeOrderGoodsService.delByOrderId(id);
        GoodsInfo goodsInfo = param.getGoodsInfo();
        KwoTradeOrderGoods goods = BeanUtils.copyProperties(goodsInfo, KwoTradeOrderGoods.class);
        if (Objects.nonNull(goods) && Objects.nonNull(goods.getGoodsId())) {
            GoodsDetail goodsDetail = goodsInfoService.getDetailById(goods.getGoodsId());
            if (Objects.isNull(goodsDetail) || !Objects.equals(goodsDetail.getStatus(), 1)
                    || Objects.equals(goodsDetail.getDelFlag(), Global.YES)) {
                throw new BusinessException("商品不存在或已下架！");
            }
            goods.setTOrderId(id).setTOrderNo(tOrderNo).setGoodsType(goodsDetail.getGoodsType());
            kwoTradeOrderGoodsService.insert(goods);
            order.setGoodsId(goodsDetail.getId()).setUnit(goodsDetail.getUnit()).setUnitPrice(goods.getUnitPrice())
                    .setGoodsName(goodsDetail.getName()).setGoodsType(goodsDetail.getGoodsType()).setGoodsCode(goodsDetail.getCode())
                    .setGoodsTaxRate(goodsDetail.getTaxRate()).setGoodsSpec(goodsDetail.getSpec());
            BeanUtils.copyProperties(goodsInfo, order);
        }
        //单位信息
        kwoTradeOrderUnitService.delByOrderId(id);
        List<UnitInfo> unitInfos = param.getUnitInfo();
        if (CollectionUtils.isNotEmpty(unitInfos)) {
            List<KwoTradeOrderUnit> list = new ArrayList<>(unitInfos.size());
            List<Long> entIds = unitInfos.stream().map(UnitInfo::getEntId).distinct().toList();
            Map<Long, EntCacheResDto> entMap = remoteSystemService.queryEntTreeByIds(entIds);
            unitInfos.forEach(e -> {
                EntCacheResDto ent = entMap.get(e.getEntId());
                if (Objects.isNull(ent)) {
                    throw new BusinessException("企业:" + e.getFirmName() + "的一级企业信息不存在！");
                }
                KwoTradeOrderUnit unit = BeanUtils.copyProperties(e, KwoTradeOrderUnit.class);
                unit.setTOrderId(id).setTOrderNo(tOrderNo).setTopEntId(ent.getId());
                list.add(unit);
                if (Objects.equals(e.getUnitType(), DictEnum.TORDER_UNIT_TYPE_1.getValue())) {
                    order.setProcureEntId(e.getEntId()).setProcureTopEntId(unit.getTopEntId()).setProcureFirmName(e.getFirmName())
                            .setProcureContacts(e.getContacts()).setProcurePhone(e.getPhone());
                } else {
                    order.setSupplyEntId(e.getEntId()).setSupplyTopEntId(unit.getTopEntId()).setSupplyFirmName(e.getFirmName())
                            .setSupplyContacts(e.getContacts()).setSupplyPhone(e.getPhone());
                }
            });
            kwoTradeOrderUnitService.insertBatch(list);
        }
        //地址信息
        kwoTradeOrderAddressService.delByOrderId(id);
        List<AddressInfo> addressInfos = param.getAddressInfo();
        if (CollectionUtils.isNotEmpty(addressInfos)) {
            List<KwoTradeOrderAddress> list = new ArrayList<>(addressInfos.size());
            addressInfos.forEach(e -> {
                KwoTradeOrderAddress address = BeanUtils.copyProperties(e, KwoTradeOrderAddress.class);
                address.setTOrderId(id).setTOrderNo(tOrderNo);
                list.add(address);
                if (Objects.equals(e.getAddressType(), DictEnum.TORDER_ADDRESS_TYPE_1.getValue())) {
                    order.setLoadName(e.getName()).setLoadType(e.getType()).setLoadContacts(e.getContacts())
                            .setLoadPhone(e.getPhone()).setLoadCityCode(String.valueOf(e.getCityCode())).setLoadCityName(e.getCityName())
                            .setLoadDetailAddress(e.getDetailAddress()).setLoadLat(e.getLat()).setLoadLng(e.getLng());
                } else {
                    order.setUnloadName(e.getName()).setUnloadType(e.getType()).setUnloadContacts(e.getContacts())
                            .setUnloadPhone(e.getPhone()).setUnloadCityCode(String.valueOf(e.getCityCode())).setUnloadCityName(e.getCityName())
                            .setUnloadDetailAddress(e.getDetailAddress()).setUnloadLat(e.getLat()).setUnloadLng(e.getLng());
                }
            });
            kwoTradeOrderAddressService.insertBatch(list);
        }
        //合同信息
        kwoTradeOrderContractService.delByOrderId(id);
        ContractInfo contractInfo = param.getContractInfo();
        KwoTradeOrderContract contract = BeanUtils.copyProperties(contractInfo, KwoTradeOrderContract.class);
        if (Objects.nonNull(contract)) {
            contract.setTOrderId(id).setTOrderNo(tOrderNo);
            kwoTradeOrderContractService.insert(contract);
            BeanUtils.copyProperties(contractInfo, order);
        }
        //状态信息（草稿更新不加状态记录）
        if (!isUpdate || !Objects.equals(DictEnum.TORDER_STATUS_0.getValue(), String.valueOf(tradeOrder.getStatus()))) {
            KwoTradeOrderTrack track = new KwoTradeOrderTrack();
            track.setTOrderId(id).setTOrderNo(tOrderNo).setStatus(tradeOrder.getStatus()).setRemark(tradeOrder.getRemark());
            kwoTradeOrderTrackService.insert(track);
        }
        int method = isUpdate ? 2 : 1;
        //存MongoDb
        saveMongoDb(method, order);
    }

    /**
     * @desc: mq保存mongodb
     * @author: yzc
     * @date: 2023-07-17 8:43
     * @Param method:
     * @Param order:
     * @return: void
     */
    private void saveMongoDb(Integer method, Object order) {
        SckwBusSum busSum = new SckwBusSum();
        busSum.setBusSumType("tradeOrder");
        busSum.setMethod(method);
        busSum.setObject(order);
        streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
    }


    /**
     * @desc: 代客下单草稿
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addValetOrderDraft(ValetOrderDraftParam param) {
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(OrderGenerateUtils.generateOrderNo(ORDER_NO_PREFIX))
                .setUnit(Objects.nonNull(param.getGoodsInfo()) ? param.getGoodsInfo().getUnit() : null)
                .setSource(DictEnum.TORDER_SOURCE_2.getValue()).setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_0.getValue()));
        kwoTradeOrderMapper.insert(order);
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);
    }

    /**
     * @desc: 采购下单提交
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addPurchaseOrderSubmit(PurchaseOrderParam param) {
        GoodsInfo goodsInfo = param.getGoodsInfo();
        if (Objects.isNull(goodsInfo.getPriceRangeId())) {
            throw new BusinessException("采购下单价格梯度信息不能为空！");
        }
        OrderCheckDTO orderCheckDTO = BeanUtils.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheckDTO, param.getUnitInfo());
        orderCheckDTO.setGoodsId(goodsInfo.getGoodsId()).setUnitPrice(goodsInfo.getUnitPrice())
                .setOrderSource(DictEnum.TORDER_SOURCE_1.getValue());
        orderCheck(orderCheckDTO, false);
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(OrderGenerateUtils.generateOrderNo(ORDER_NO_PREFIX))
                .setUnit(param.getGoodsInfo().getUnit()).setSource(DictEnum.TORDER_SOURCE_1.getValue())
                .setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_1.getValue()));
        kwoTradeOrderMapper.insert(order);
        //扣减库存
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);
    }

    /**
     * @desc: 获取采购销售顶级企业id
     * @author: yzc
     * @date: 2023-07-25 10:03
     * @Param orderCheckDTO:
     * @Param unitInfo:
     * @return: void
     */
    private void getTopEnt(OrderCheckDTO orderCheckDTO, List<UnitInfo> unitInfo) {
        List<Long> entIds = unitInfo.stream().map(UnitInfo::getEntId).toList();
        Map<Long, EntCacheResDto> entMap = remoteSystemService.queryEntTreeByIds(entIds);
        unitInfo.forEach(e -> {
            EntCacheResDto ent = entMap.get(e.getEntId());
            if (Objects.isNull(ent)) {
                log.error("企业：{}找不到对应一级企业信息", e.getEntId());
                throw new BusinessException("一级企业信息不存在！");
            }
            if (Objects.equals(e.getUnitType(), DictEnum.TORDER_UNIT_TYPE_1.getValue())) {
                orderCheckDTO.setProcureTopEntId(entMap.get(e.getEntId()).getId());
            } else {
                orderCheckDTO.setSupplyTopEntId(entMap.get(e.getEntId()).getId());
            }
        });
    }

    /**
     * @desc: 订单提交校验
     * @author: yzc
     * @date: 2023-07-14 14:46
     * @Param param: 订单校验参数
     * @Param isAcceptanceOrder: 是否受理订单
     * @return: void
     */
    private void orderCheck(OrderCheckDTO param, Boolean isAcceptanceOrder) {
        BigDecimal amount = param.getAmount();
        String trading = param.getTrading();
        BigDecimal price = param.getPrice();
        if (!isAcceptanceOrder && price.compareTo(amount.multiply(param.getUnitPrice())) != 0) {
            throw new BusinessException("订单总金额不等于商品单价*订单总量！");
        }
        KwpGoods goods = goodsInfoService.getGoodsById(param.getGoodsId());
        if (Objects.isNull(goods) || Objects.equals(goods.getDelFlag(), Global.YES) || !Objects.equals(goods.getStatus(), 1)) {
            throw new BusinessException("商品不存在或已下架！");
        }
        if (goods.getAmount().compareTo(amount) < 0) {
            throw new BusinessException("商品库存不足，请联系供应方！");
        }
        BigDecimal advancePrice = goods.getAdvancePrice().multiply(new BigDecimal("10000"));
        //直接采购下单才校验预付款限额
        if (Objects.equals(param.getOrderSource(), DictEnum.TORDER_SOURCE_1.getValue()) && trading.startsWith("1") && price.compareTo(advancePrice) < 0) {
            throw new BusinessException("您的订单总额未达到预付限额，请确认");
        }
        if (trading.startsWith("1")) {
            R<List<WalletDto>> wallet = payCenterDubboService.wallet(param.getProcureTopEntId(), ChannelEnum.getByCode(trading), param.getSupplyTopEntId());
            if (Objects.isNull(wallet) || Objects.equals(wallet.getCode(), 0)) {
                throw new BusinessException("校验预付钱包异常，请联系管理员！");
            }
            List<WalletDto> data = wallet.getData();
            if (CollectionUtils.isEmpty(data)) {
                throw new BusinessException("检测尚未创建对应预付款清单，请先创建！");
            }
            long money = data.get(0).getMoney();
            if (money < advancePrice.multiply(new BigDecimal("100")).longValueExact()) {
                throw new BusinessException("您的预付清单可用余额不足，请先充值！");
            }
        }
    }

    /**
     * @desc: 代客下单提交
     * @author: yzc
     * @date: 2023-07-07 15:32
     * @Param param:
     * @return: void
     */
    @Transactional(rollbackFor = Exception.class)
    public void addValetOrderSubmit(ValetOrderParam param) {
        OrderCheckDTO orderCheck = BeanUtils.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, param.getUnitInfo());
        orderCheck.setGoodsId(param.getGoodsInfo().getGoodsId()).setUnitPrice(param.getGoodsInfo().getUnitPrice())
                .setOrderSource(DictEnum.TORDER_SOURCE_2.getValue());
        orderCheck(orderCheck, false);
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(OrderGenerateUtils.generateOrderNo(ORDER_NO_PREFIX))
                .setUnit(param.getGoodsInfo().getUnit()).setSource(DictEnum.TORDER_SOURCE_2.getValue());
        String contractStatus = param.getContractInfo().getContractStatus();
        if (Objects.equals(contractStatus, DictEnum.CONTRACT_STATUS_0.getValue())) {
            order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_3.getValue()));
        } else if (Objects.equals(contractStatus, DictEnum.CONTRACT_STATUS_1.getValue())) {
            order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_4.getValue()));
        } else {
            throw new BusinessException("Invalid contract status");
        }
        kwoTradeOrderMapper.insert(order);
        //扣减库存
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);
    }

    /**
     * @desc: 订单详情
     * @author: yzc
     * @date: 2023-07-07 15:32
     * @Param id:
     * @return: com.sckw.order.model.vo.res.OrderDetail
     */
    public OrderDetailRes detail(Long id) {
        KwoTradeOrder order = getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("不存在该订单！");
        }
        //订单基本信息
        OrderDetailRes detail = BeanUtils.copyProperties(order, OrderDetailRes.class);
        UserCacheResDto createUser = remoteSystemService.queryUserCacheById(detail.getCreateBy());
        EntCacheResDto ent = remoteSystemService.queryEntCacheById(detail.getEntId());
        detail.setFirmName(Objects.isNull(ent) ? null : ent.getFirmName())
                .setCreateByName(Objects.isNull(createUser) ? null : createUser.getName())
                .setTradingLabel(DictEnum.getLabel(DictTypeEnum.TRADE_TYPE.getType(), detail.getTrading()))
                .setPickupTypeLabel(DictEnum.getLabel(DictTypeEnum.PICKUP_TYPE.getType(), detail.getPickupType()))
                .setDeliveryTypeLabel(DictEnum.getLabel(DictTypeEnum.DELIVERY_TYPE.getType(), detail.getDeliveryType()))
                .setSourceLabel(DictEnum.getLabel(DictTypeEnum.TORDER_SOURCE.getType(), detail.getSource()))
                .setStatusLabel(DictEnum.getLabel(DictTypeEnum.TORDER_STATUS.getType(), String.valueOf(detail.getStatus())));
        //商品信息
        KwoTradeOrderGoods orderGoods = kwoTradeOrderGoodsService.getByOrderId(id);
        if (Objects.nonNull(orderGoods)) {
            KwpGoods goods = goodsInfoService.getGoodsById(orderGoods.getGoodsId());
            if (Objects.nonNull(goods)) {
                EntCacheResDto entCache = remoteSystemService.queryEntCacheById(goods.getEntId());
                GoodsInfoDetailRes goodsDetail = new GoodsInfoDetailRes();
                goodsDetail.setGoodsTypeLabel(DictEnum.getLabel(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), goods.getGoodsType()))
                        .setUnitLabel(DictEnum.getLabel(DictTypeEnum.UNIT_TYPE.getType(), goods.getUnit())).setGoodsAmount(goods.getAmount())
                        .setTaxRateLabel(DictEnum.getLabel(DictTypeEnum.TAX_RATE.getType(), goods.getTaxRate()))
                        .setGoodsId(goods.getId()).setCode(goods.getCode()).setName(goods.getName())
                        .setGoodsType(goods.getGoodsType()).setTaxRate(goods.getTaxRate()).setSpec(goods.getSpec())
                        .setUnit(goods.getUnit()).setPriceRangeId(orderGoods.getPriceRangeId()).setUnitPrice(orderGoods.getUnitPrice())
                        .setSkuId(orderGoods.getSkuId()).setCollectionUnitId(goods.getEntId())
                        .setCollectionUnit(Objects.isNull(entCache) ? null : entCache.getFirmName());
                detail.setGoodsInfo(goodsDetail);
            }
        }

        //单位信息
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(id);
        if (CollectionUtils.isNotEmpty(units)) {
            List<UnitInfoDetailRes> unitInfos = BeanUtils.copyToList(units, UnitInfoDetailRes.class);
            unitInfos.forEach(e -> {
                e.setUnitTypeLabel(DictEnum.getLabel(DictTypeEnum.TORDER_UNIT_TYPE.getType(), e.getUnitType()));
            });
            detail.setUnitInfo(unitInfos);
        }
        //地址信息
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderId(id);
        if (CollectionUtils.isNotEmpty(addressList)) {
            List<AddressInfoDetailRes> addressInfoDetails = BeanUtils.copyToList(addressList, AddressInfoDetailRes.class);
            addressInfoDetails.forEach(e -> {
                e.setAddressTypeLabel(DictEnum.getLabel(DictTypeEnum.TORDER_ADDRESS_TYPE.getType(), e.getAddressType()));
                e.setTypeLabel(DictEnum.getLabel(DictTypeEnum.ADDRESS_TYPE.getType(), e.getType()));
            });
            detail.setAddressInfo(addressInfoDetails);
        }
        //合同信息
        KwoTradeOrderContract contract = kwoTradeOrderContractService.getByOrderId(id);
        if (Objects.nonNull(contract)) {
            ContractInfo contractInfo = BeanUtils.copyProperties(contract, ContractInfo.class);
            Map<Long, ContractCommonInfoResDto> contractMap = remoteContractService.queryContractBaseInfo(List.of(contractInfo.getContractId()));
            ContractCommonInfoResDto contractRes = contractMap.get(contractInfo.getContractId());
            if (Objects.nonNull(contractRes)) {
                contractInfo.setContractName(contractRes.getContactName());
                contractInfo.setContractSigningWay(contractRes.getSigningWayName());
            }
            detail.setContractInfo(contractInfo);
        }
        return detail;
    }

    /**
     * @desc: 修改订单
     * @author: yzc
     * @date: 2023-07-07 15:34
     * @Param param:
     * @return: void
     */
    public void update(UpdateOrderParam param) {
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        String source = order.getSource();
        String status = String.valueOf(order.getStatus());
        if ((!Objects.equals(status, DictEnum.TORDER_STATUS_0.getValue()) && !Objects.equals(status, DictEnum.TORDER_STATUS_2.getValue()))
                && Objects.equals(source, DictEnum.TORDER_SOURCE_1.getValue())) {
            throw new BusinessException("采购下单只能修改已保存及已退回状态的订单！");
        }
        if (Objects.equals(source, DictEnum.TORDER_SOURCE_2.getValue()) && !Objects.equals(status, DictEnum.TORDER_STATUS_0.getValue())) {
            throw new BusinessException("代客下单只能修改已保存状态的订单！");
        }
        if (kwoTradeOrderUnitService.entMatch(param.getId(), LoginUserHolder.getEntId(), source)) {
            throw new BusinessException("无权限修改此订单！");
        }
        if (Objects.equals(param.getOperateType(), 1)) {
            checkParams(param, source);
            if (Objects.equals(source, DictEnum.TORDER_SOURCE_1.getValue())) {
                order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_1.getValue()));
            } else {
                String contractStatus = param.getContractInfo().getContractStatus();
                if (Objects.equals(contractStatus, DictEnum.CONTRACT_STATUS_0.getValue())) {
                    order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_3.getValue()));
                } else if (Objects.equals(contractStatus, DictEnum.CONTRACT_STATUS_1.getValue())) {
                    order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_4.getValue()));
                } else {
                    throw new BusinessException("Invalid contract status");
                }
            }
            OrderCheckDTO orderCheck = BeanUtils.copyProperties(param, OrderCheckDTO.class);
            getTopEnt(orderCheck, param.getUnitInfo());
            orderCheck.setGoodsId(param.getGoodsInfo().getGoodsId()).setUnitPrice(param.getGoodsInfo().getUnitPrice())
                    .setOrderSource(source);
            orderCheck(orderCheck, false);
            //扣减库存
            HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                throw new BusinessException(updateResult.getMsg());
            }
        }
        order.setAmount(param.getAmount()).setUnit(Objects.isNull(param.getGoodsInfo()) ? null : param.getGoodsInfo().getUnit())
                .setPrice(param.getPrice()).setTrading(param.getTrading()).setPickupType(param.getPickupType())
                .setDeliveryType(param.getDeliveryType()).setStartTime(param.getStartTime()).setEndTime(param.getEndTime())
                .setRemark(param.getRemark());
        kwoTradeOrderMapper.updateById(order);
        ValetOrderParam valetOrderParam = BeanUtils.copyProperties(param, ValetOrderParam.class);

        addOtherOrderInfo(order, valetOrderParam, true);
    }


    private void checkParams(UpdateOrderParam param, String source) {
        if (Objects.isNull(param.getAmount())) {
            throw new BusinessException("订单总量不能为空且！");
        }
        if (Objects.isNull(param.getPrice())) {
            throw new BusinessException("订单金额不能为空且！");
        }
        if (StringUtils.isBlank(param.getTrading())) {
            throw new BusinessException("交易方式不能为空!");
        }
        if (StringUtils.isBlank(param.getPickupType())) {
            throw new BusinessException("提货方式不能为空!");
        }
        if (Objects.isNull(param.getStartTime())) {
            throw new BusinessException("开始时间不能为空！");
        }
        if (Objects.isNull(param.getEndTime())) {
            throw new BusinessException("结束时间不能为空！");
        }
        ContractInfo contractInfo = param.getContractInfo();
        if (Objects.equals(source, DictEnum.TORDER_SOURCE_2.getValue())) {
            if (StringUtils.isBlank(param.getDeliveryType())) {
                throw new BusinessException("交付类型不能为空!");
            }
            if (Objects.isNull(contractInfo)) {
                throw new BusinessException("代客下单合同信息不能为空");
            }
            if (Objects.isNull(contractInfo.getContractId())) {
                throw new BusinessException("合同id不能为空！");
            }
            if (StringUtils.isBlank(contractInfo.getContractNo())) {
                throw new BusinessException("合同编号不能为空！");
            }
            if (StringUtils.isBlank(contractInfo.getContractName())) {
                throw new BusinessException("合同名称不能为空！");
            }
            if (StringUtils.isBlank(contractInfo.getContractSigningWay())) {
                throw new BusinessException("合同签约方式不能为空！");
            }
            if (StringUtils.isBlank(contractInfo.getContractStatus())) {
                throw new BusinessException("合同状态不能为空！");
            }
        }
        GoodsInfo goodsInfo = param.getGoodsInfo();
        if (Objects.isNull(goodsInfo)) {
            throw new BusinessException("商品信息不能为空！");
        }
        if (Objects.isNull(goodsInfo.getGoodsId())) {
            throw new BusinessException("商品id不能为空！");
        }
        if (StringUtils.isBlank(goodsInfo.getUnit())) {
            throw new BusinessException("商品单位不能为空！");
        }
        if (Objects.isNull(goodsInfo.getPriceRangeId()) && Objects.equals(source, DictEnum.TORDER_SOURCE_1.getValue())) {
            throw new BusinessException("价格段id不能为空！");
        }
        if (Objects.isNull(goodsInfo.getUnitPrice()) || goodsInfo.getUnitPrice().compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("订单成交单价不能为空且不能为负数！");
        }

        List<UnitInfo> unitInfos = param.getUnitInfo();
        if (CollectionUtils.isEmpty(unitInfos)) {
            throw new BusinessException("单位信息不能为空！");
        }
        unitInfos.forEach(e -> {
            if (Objects.isNull(e.getUnitType())) {
                throw new BusinessException("单位类型不能为空！");
            }
            if (Objects.isNull(e.getEntId())) {
                throw new BusinessException("企业id不能为空！");
            }
            if (StringUtils.isBlank(e.getFirmName())) {
                throw new BusinessException("企业名称不能为空！");
            }
            if (StringUtils.isBlank(e.getContacts())) {
                throw new BusinessException("联系人姓名不能为空！");
            }
            if (StringUtils.isBlank(e.getPhone())) {
                throw new BusinessException("联系电话不能为空！");
            }
        });
        List<AddressInfo> addressInfos = param.getAddressInfo();
        if (CollectionUtils.isEmpty(addressInfos)) {
            throw new BusinessException("地址信息不能为空！");
        }
        addressInfos.forEach(e -> {
            if (StringUtils.isBlank(e.getAddressType())) {
                throw new BusinessException("地址类型不能为空！");
            }
            if (StringUtils.isBlank(e.getName())) {
                throw new BusinessException("地址名称不能为空！");
            }
            if (StringUtils.isBlank(e.getType())) {
                throw new BusinessException("地址类型不能为空！");
            }
            if (StringUtils.isBlank(e.getContacts())) {
                throw new BusinessException("联系人姓名不能为空！");
            }
            if (StringUtils.isBlank(e.getPhone())) {
                throw new BusinessException("联系电话不能为空！");
            }
            if (Objects.isNull(e.getCityCode())) {
                throw new BusinessException("所在地区code不能为空！");
            }
            if (StringUtils.isBlank(e.getCityName())) {
                throw new BusinessException("所属区域名称不能为空！");
            }
            if (StringUtils.isBlank(e.getDetailAddress())) {
                throw new BusinessException("详细地址不能为空！");
            }
            if (StringUtils.isBlank(e.getLat())) {
                throw new BusinessException("纬度不能为空！");
            }
            if (StringUtils.isBlank(e.getLng())) {
                throw new BusinessException("经度不能为空！");
            }
        });

    }

    /**
     * @desc: 订单受理
     * @author: yzc
     * @date: 2023-07-14 16:59
     * @Param param:
     * @return: void
     */
    public void acceptanceOrder(AcceptanceOrderParam param) {
        if (param.getPrice().compareTo(param.getUnitPrice().multiply(param.getAmount())) != 0) {
            throw new BusinessException("订单总金额不等于商品单价*订单总量！");
        }
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(DictEnum.TORDER_STATUS_1.getValue(), String.valueOf(order.getStatus()))) {
            throw new BusinessException("订单状态不为待受理！");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), DictEnum.TORDER_UNIT_TYPE_2.getValue())) {
            throw new BusinessException("无订单操作权限！");
        }
        KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(order.getId());
        if (Objects.isNull(goods)) {
            throw new BusinessException("订单商品信息异常！");
        }
        //受理订单总量-原订单总量=订单变化量
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(order.getId());
        List<UnitInfo> unitInfos = BeanUtils.copyToList(units, UnitInfo.class);
        if (CollectionUtils.isEmpty(unitInfos)) {
            throw new BusinessException("订单企业信息异常！");
        }
        BigDecimal amount = param.getAmount().subtract(order.getAmount());
        OrderCheckDTO orderCheck = BeanUtils.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, unitInfos);
        orderCheck.setGoodsId(goods.getGoodsId()).setAmount(amount);
        orderCheck(orderCheck, true);
        //更新订单信息
        BeanUtils.copyProperties(param, order);
        String contractStatus = param.getContractInfo().getContractStatus();
        if (Objects.equals(contractStatus, DictEnum.CONTRACT_STATUS_0.getValue())) {
            order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_3.getValue()));
        } else if (Objects.equals(contractStatus, DictEnum.CONTRACT_STATUS_1.getValue())) {
            order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_4.getValue()));
        } else {
            throw new BusinessException("Invalid contract status");
        }
        kwoTradeOrderMapper.updateById(order);
        //保存合同信息
        ContractInfo contractInfo = param.getContractInfo();
        KwoTradeOrderContract contract = BeanUtils.copyProperties(contractInfo, KwoTradeOrderContract.class);
        contract.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo());
        kwoTradeOrderContractService.insert(contract);
        //订单状态记录
        KwoTradeOrderTrack track = new KwoTradeOrderTrack();
        track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setStatus(order.getStatus());
        kwoTradeOrderTrackService.insert(track);
        //更新库存
        if (amount.compareTo(BigDecimal.ZERO) != 0) {
            HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), amount);
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                throw new BusinessException(updateResult.getMsg());
            }
        }
        //更新mongodb
        SckwTradeOrder updateParam = BeanUtils.copyProperties(param, SckwTradeOrder.class);
        updateParam.setTOrderId(param.getId()).setStatus(order.getStatus()).setContractId(contractInfo.getContractId())
                .setContractNo(contractInfo.getContractNo()).setContractName(contractInfo.getContractName())
                .setContractSigningWay(contractInfo.getContractSigningWay()).setUpdateBy(LoginUserHolder.getUserId())
                .setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
        saveMongoDb(3, updateParam);

    }

    /**
     * @desc: 订单驳回
     * @author: yzc
     * @date: 2023-07-14 17:00
     * @Param param:
     * @return: void
     */
    public void rejectOrder(RejectOrderParam param) {
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(DictEnum.TORDER_STATUS_1.getValue(), String.valueOf(order.getStatus()))) {
            throw new BusinessException("订单状态不为待受理！");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), DictEnum.TORDER_UNIT_TYPE_2.getValue())) {
            throw new BusinessException("无订单操作权限！");
        }
        order.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_2.getValue()));
        kwoTradeOrderMapper.updateById(order);
        //订单状态记录
        KwoTradeOrderTrack track = new KwoTradeOrderTrack();
        track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setRemark(param.getRemark()).setStatus(order.getStatus());
        kwoTradeOrderTrackService.insert(track);
        //释放商品库存
        KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(order.getId());
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), order.getAmount().negate());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        //mongodb更新订单状态
        SckwTradeOrder updateParam = new SckwTradeOrder();
        updateParam.setTOrderId(order.getId()).setStatus(order.getStatus()).setUpdateBy(LoginUserHolder.getUserId())
                .setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
        saveMongoDb(3, updateParam);
    }

    /**
     * @desc: 订单驳回查询
     * @author: yzc
     * @date: 2023-07-14 17:00
     * @Param id:
     * @return: java.lang.String
     */
    public String rejectReason(Long id) {
        KwoTradeOrder order = getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), null)) {
            throw new BusinessException("无订单操作权限！");
        }
        KwoTradeOrderTrack track = kwoTradeOrderTrackService.getByOrderId(id, Integer.valueOf(DictEnum.TORDER_STATUS_2.getValue()));

        return Objects.isNull(track) ? null : track.getRemark();
    }

    /**
     * @desc: 完结订单
     * @author: yzc
     * @date: 2023-07-14 17:01
     * @Param param:
     * @return: void
     */
    public void completeOrder(CompleteOrderParam param) {
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(String.valueOf(order.getStatus()), DictEnum.TORDER_STATUS_4.getValue())) {
            throw new BusinessException("执行中的订单才能完结订单！");
        }
        if (kwoTradeOrderUnitService.entMatch(param.getId(), LoginUserHolder.getEntId(), DictEnum.TORDER_UNIT_TYPE_2.getValue())) {
            throw new BusinessException("无订单操作权限！");
        }
        if (transportDubboService.checkLogisticsOrderByTradeOrderId(param.getId())){
            throw new BusinessException("订单存在未完成的物流托运，不可完结！");
        }
        String lockKey = String.format(RedisConstant.TORDER_UPDATE_AMOUNT_KEY, param.getId());
        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
            throw new BusinessException("业务繁忙，请稍后再试!");
        }
        try {
            order.setActualAmount(param.getActualAmount()).setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_5.getValue()));
            kwoTradeOrderMapper.updateById(order);
            //订单状态记录
            KwoTradeOrderTrack track = new KwoTradeOrderTrack();
            track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setRemark(param.getRemark()).setStatus(order.getStatus());
            kwoTradeOrderTrackService.insert(track);
            if (param.getActualAmount().compareTo(order.getAmount()) != 0) {
                KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(param.getId());
                if (Objects.isNull(goods)) {
                    throw new BusinessException("商品信息异常！");
                }
                //更新库存
                BigDecimal amount = param.getActualAmount().subtract(order.getAmount());
                HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), amount);
                if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                    throw new BusinessException(updateResult.getMsg());
                }
            }
            //mongodb更新订单状态
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(order.getId()).setActualAmount(order.getActualAmount()).setStatus(order.getStatus())
                    .setUpdateBy(LoginUserHolder.getUserId()).setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
            saveMongoDb(3, updateParam);
        } finally {
            RedissonUtils.unlock(lockKey);
        }

    }


    /**
     * @desc: 批量删除
     * @author: yzc
     * @date: 2023-07-17 20:35
     * @Param param:
     * @return: void
     */
    public void batchDelete(BatchDeleteParam param) {
        List<Long> ids = StringUtils.splitStrToList(param.getIds(), ",", Long.class);
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(KwoTradeOrder::getId, ids).ne(KwoTradeOrder::getStatus, 0).eq(KwoTradeOrder::getDelFlag, Global.NO);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            throw new BusinessException("删除操作仅针对“已保存”状态的订单");
        }
        if (kwoTradeOrderUnitService.entBatchMatch(ids, LoginUserHolder.getEntId(), String.valueOf(param.getOrderType()))) {
            throw new BusinessException("无订单操作权限！");
        }
        LambdaUpdateWrapper<KwoTradeOrder> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(KwoTradeOrder::getDelFlag, Global.YES).in(KwoTradeOrder::getId, ids);
        kwoTradeOrderMapper.update(null, updateWrapper);
        kwoTradeOrderGoodsService.delByOrderIds(ids);
        kwoTradeOrderUnitService.delByOrderIds(ids);
        kwoTradeOrderAddressService.delByOrderIds(ids);
        kwoTradeOrderContractService.delByOrderIds(ids);
        //更新mongodb
        ids.forEach(id -> {
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(id).setDelFlag(Global.YES).setUpdateBy(LoginUserHolder.getUserId())
                    .setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
            saveMongoDb(3, updateParam);
        });

    }

    /**
     * @desc: 根据id获取订单
     * @author: yzc
     * @date: 2023-07-13 17:14
     * @Param id:
     * @return: com.sckw.order.model.KwoTradeOrder
     */
    public KwoTradeOrder getById(Long id) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwoTradeOrder::getId, id).eq(KwoTradeOrder::getDelFlag, Global.NO).last("LIMIT 1");
        return kwoTradeOrderMapper.selectOne(wrapper);
    }

    /**
     * @desc: 根据id更新
     * @author: yzc
     * @date: 2023-07-20 10:24
     * @Param order:
     * @return: void
     */
    public void updateById(KwoTradeOrder order) {
        kwoTradeOrderMapper.updateById(order);
    }


    /**
     * @desc: 根据订单ids获取待签约订单
     * @author: yzc
     * @date: 2023-07-20 14:10
     * @Param tOrderIds:
     * @return: java.util.List<com.sckw.order.model.KwoTradeOrder>
     */
    public List<KwoTradeOrder> getWaitSignByIds(List<Long> tOrderIds) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwoTradeOrder::getStatus, Integer.valueOf(DictEnum.TORDER_STATUS_3.getValue()))
                .in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getDelFlag, Global.NO);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        return CollectionUtils.emptyIfNull(list);
    }

    /**
     * @desc: 根据订单ids变更待签约订单为执行中
     * @author: yzc
     * @date: 2023-07-20 11:57
     * @Param tOrderIds:
     * @Param updateBy:
     * @return: void
     */
    public void contractCompletedUpdate(List<Long> tOrderIds, Long updateBy) {
        LambdaUpdateWrapper<KwoTradeOrder> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getStatus, Integer.valueOf(DictEnum.TORDER_STATUS_3.getValue()))
                .eq(KwoTradeOrder::getDelFlag, Global.NO).set(KwoTradeOrder::getUpdateBy, updateBy)
                .set(KwoTradeOrder::getStatus, Integer.valueOf(DictEnum.TORDER_STATUS_4.getValue()));
        kwoTradeOrderMapper.update(null, wrapper);
    }

    /**
     * @desc: 获取贸易订单地址下拉列表
     * @author: yzc
     * @date: 2023-08-02 17:28
     * @return: com.sckw.order.model.vo.res.AddressDropListRes
     */
    public AddressDropListRes getAddressDropList() {
        AddressDropListRes res = new AddressDropListRes();
        Long entId = LoginUserHolder.getEntId();
        //一级企业匹配筛选订单id
        List<KwoTradeOrderUnit> unitInfo = kwoTradeOrderUnitService.getByTopEntId(entId);
        if (CollectionUtils.isEmpty(unitInfo)) {
            return res;
        }
        Set<Long> tOrderIds = unitInfo.stream().map(KwoTradeOrderUnit::getTOrderId).collect(Collectors.toSet());
        //订单ids获取地址信息
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderIds(tOrderIds);
        if (CollectionUtils.isEmpty(addressList)) {
            return res;
        }
        //装卸货地址类型分组获取装卸货cityCodes
        Map<String, List<Integer>> map = addressList.stream().collect(Collectors.
                groupingBy(KwoTradeOrderAddress::getAddressType, Collectors.mapping(KwoTradeOrderAddress::getCityCode, Collectors.toList())));
        //装货地址下拉列表树
        List<AreaTreeFrontResDto> loadTree = remoteSystemService.queryAreaTreeFrontByCodeList(map.get(DictEnum.TORDER_ADDRESS_TYPE_1.getValue()));
        //卸货地址下拉列表树
        List<AreaTreeFrontResDto> unloadTree = remoteSystemService.queryAreaTreeFrontByCodeList(map.get(DictEnum.TORDER_ADDRESS_TYPE_2.getValue()));
        res.setLoadAddressList(loadTree).setUnloadAddressList(unloadTree);
        return res;
    }
}
