package com.yc.ship.module.trade.service.supplier.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yc.ship.framework.common.exception.ErrorCode;
import com.yc.ship.framework.common.exception.ServiceException;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.object.ObjectUtils;
import com.yc.ship.module.product.api.ProductApi;
import com.yc.ship.module.product.api.dto.SupplierRespDTO;
import com.yc.ship.module.resource.ResourceApi;
import com.yc.ship.module.trade.api.dto.TradeBindVisitorReqDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderCreateReqDTO;
import com.yc.ship.module.trade.controller.app.ota.vo.OtaVoucherVO;
import com.yc.ship.module.trade.convert.order.TradeOrderConvert;
import com.yc.ship.module.trade.dal.dataobject.order.TradeDetailBaseDO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderDO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeVisitorDO;
import com.yc.ship.module.trade.dal.dataobject.refund.RefundDO;
import com.yc.ship.module.trade.dal.dataobject.supplier.SupplierRefundDO;
import com.yc.ship.module.trade.dal.dataobject.supplier.SupplierRetryRecordDO;
import com.yc.ship.module.trade.dal.dataobject.supplier.TradeSupplierOrderDO;
import com.yc.ship.module.trade.enums.RefundStatusEnum;
import com.yc.ship.module.trade.enums.TradeOrderOperateTypeEnum;
import com.yc.ship.module.trade.enums.TradeOrderStatusEnum;
import com.yc.ship.module.trade.framework.annotation.TradeOrderLog;
import com.yc.ship.module.trade.framework.common.ExceptionUtils;
import com.yc.ship.module.trade.framework.common.TradeOrderLogUtils;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.service.order.bo.*;
import com.yc.ship.module.trade.service.refund.TradeRefundRepositoryService;
import com.yc.ship.module.trade.service.refund.bo.RefundAuditNotifyBO;
import com.yc.ship.module.trade.service.refund.bo.TradeRefundBO;
import com.yc.ship.module.trade.service.supplier.SupplierTradeService;
import com.yc.ship.module.trade.service.supplier.TradeSupplierCallbackService;
import com.yc.ship.module.trade.service.supplier.TradeSupplierOrderRepositoryService;
import com.yc.ship.module.trade.service.supplier.TradeSupplierService;
import com.yc.ship.module.trade.service.supplier.bo.*;
import com.yc.ship.module.trade.utils.TradeUUCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

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

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.product.enums.YesOrNoEnum.YES;
import static com.yc.ship.module.trade.enums.ApiConstants.SUPPLIER_RETRY_TYPE_PAY;
import static com.yc.ship.module.trade.enums.ApiConstants.SUPPLIER_RETRY_TYPE_REFUND;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.*;
import static com.yc.ship.module.trade.enums.TradeConstants.FAIL;
import static com.yc.ship.module.trade.enums.TradeConstants.SUCCESS;
import static com.yc.ship.module.trade.enums.TravelhubDictTypeConstants.*;
import static com.yc.ship.module.trade.service.refund.TradeRefundService.UPDATE_REFUND_SUPPLIER_LOCK;
import static com.yc.ship.module.trade.service.refund.TradeRefundService.UPDATE_SUPPLIER_ORDER_LOCK;
import static com.yc.ship.module.trade.service.supplier.SupplierTradeService.PLAT_SERVICE;
import static com.yc.ship.module.trade.utils.TradeUUCodeUtils.SUPPLIER_ORDER_PREFIX;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

/**
 * &#064;Description ：平台供应商交易service
 * &#064;Author ：qsl
 * &#064;Date ：2025/6/7 11:43
 */
@Service
@Slf4j
public class TradeSupplierServiceImpl implements TradeSupplierService {

    @Resource
    private TradeSupplierOrderRepositoryService tradeSupplierOrderRepositoryService;
    @Resource
    private TradeSupplierCallbackService tradeSupplierCallbackService;
    @Resource
    private TradeUUCodeUtils tradeUUCodeUtils;
    @Resource
    private Map<String, SupplierTradeService> allSupplierTradeService;
    @Resource
    private ProductApi productApi;
    @Resource
    private ResourceApi resourceApi;
    @Resource
    private TradeSupplierService tradeSupplierService;
    @Resource
    private TradeRefundRepositoryService tradeRefundRepositoryService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;

    @Override
    public CommonResult<TradeSupplierOrderRespBO> createOrder(TradeOrderBO tradeOrderBO) {
        try{
            //1.构建供应商订单
            List<TradeSupplierOrderBO> tradeSupplierOrderBOList = buildSupplierOrder(tradeOrderBO);
            CommonResult<TradeSupplierOrderRespBO> resp = CommonResult.success(null);
            if(CollectionUtil.isNotEmpty(tradeSupplierOrderBOList)){
                //2.创建供应商订单
                tradeSupplierOrderRepositoryService.saveOrder(tradeSupplierOrderBOList);
                //3.向供应商分别下单
                resp =  createOrderFromSupplierSystem(tradeSupplierOrderBOList);
            }

            return resp;
        }catch (ServiceException e){
            ExceptionUtils.log(log,"供应商下单失败:",e);
            return CommonResult.error(e);
        }catch (Exception e){
            log.error("供应商下单失败：",e);
            return CommonResult.error(SUPPLIER_ORDER_CREATE_FAIL);
        }
    }

    @Override
    public CommonResult<?> payOrder(TradeOrderDO tradeOrderDO) {
        //获取供应商订单
        List<TradeSupplierOrderDO> tradeSupplierOrderDOList = tradeSupplierOrderRepositoryService.getTradeSupplierOrderList(tradeOrderDO.getId());
        CommonResult<?> resp = CommonResult.success(null);
        if(CollectionUtil.isNotEmpty(tradeSupplierOrderDOList)){
            //3.向供应商分别支付
            //过滤已经出票成功的供应商订单
            tradeSupplierOrderDOList = tradeSupplierOrderDOList.stream().filter(item->ObjectUtil.notEqual(item.getOrderStatus(), TradeOrderStatusEnum.UNUSED.getStatus())).collect(Collectors.toList());
            resp =  payOrderFromSupplierSystem(tradeSupplierOrderDOList,tradeOrderDO);
        }

        return resp;
    }

    @Override
    public CommonResult<?> refund(TradeRefundBO tradeRefundBO) {
        //出票失败的订单退款只查询出票成功的供应商订单
        Integer supplierOrderStatus = ObjectUtil.equal(tradeRefundBO.getRefundDO().getOrderStatus(),TradeOrderStatusEnum.PROCESS_FAIL.getStatus())? TradeOrderStatusEnum.UNUSED.getStatus() : null;
        //1.获取供应商退款单
        List<SupplierRefundDO> supplierRefundList = tradeSupplierOrderRepositoryService.getSupplierOrderToCreateRefund(tradeRefundBO.getRefundDO().getId(),supplierOrderStatus);
        CommonResult<?> resp = CommonResult.success(null);
        if(CollectionUtil.isNotEmpty(supplierRefundList)){
            //2.创建供应商退款单
            createSupplierRefundOrder(tradeRefundBO,supplierRefundList);
            //3.向供应商分别退单
            resp =  refundFromSupplierSystem(supplierRefundList);
        }

        return resp;
    }

    @Override
    public CommonResult<?> retryRefund(Long supplierRefundId) {
        String lockKey = String.format(UPDATE_REFUND_SUPPLIER_LOCK,supplierRefundId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                //重试
                SupplierRefundDO supplierRefundDO = tradeSupplierOrderRepositoryService.getSupplierRefundById(supplierRefundId);
                Asserts.isTrue(ObjectUtil.equal(supplierRefundDO.getRefundStatus(), RefundStatusEnum.REFUND_FAIL.getStatus()),"供应商退款状态已变更，不能重试{}",supplierRefundDO.getRefundStatus());
                //添加重试记录
                SupplierRetryRecordDO supplierRetryRecordDO = tradeSupplierOrderRepositoryService.addRetryRecord(supplierRefundId,SUPPLIER_RETRY_TYPE_REFUND);
                List<SupplierRefundDO> supplierRefundDOList = new ArrayList<>();
                supplierRefundDO.setRetryCount(supplierRefundDO.getRetryCount()==null?1:supplierRefundDO.getRetryCount()+1);
                supplierRefundDOList.add(supplierRefundDO);

                CommonResult<?> resp = refundFromSupplierSystem(supplierRefundDOList);
                supplierRetryRecordDO.setReturnMsg(supplierRefundDO.getErrorMsg());
                if(resp.isError()){
                   if(ObjectUtil.equal(resp.getCode(),REFUND_AUDITING.getCode())){
                       supplierRetryRecordDO.setStatus(SUCCESS);
                   }else{
                       supplierRetryRecordDO.setStatus(FAIL);
                   }
                }else{
                    supplierRetryRecordDO.setStatus(SUCCESS);
                }

                tradeSupplierOrderRepositoryService.updateRetryRecord(supplierRetryRecordDO);
                return resp;
            }
        }catch (ServiceException e){
            ExceptionUtils.log(log,"供应商重试退款修改退款批次异常refundId:"+supplierRefundId,e);
            return CommonResult.error(e);
        }catch (Exception e){
            log.error("供应商重试退款修改退款批次异常refundId:"+supplierRefundId,e);
        } finally {
            if(lock.isLocked() && lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
        return CommonResult.error(SUPPLIER_REFUND_RETRY_EXCEPTION);
    }

    @Override
    public CommonResult<?> retryPayOrder(Long supplierOrderId) {
        String lockKey = String.format(UPDATE_SUPPLIER_ORDER_LOCK,supplierOrderId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                //重试
                TradeSupplierOrderDO tradeSupplierOrderDO = tradeSupplierOrderRepositoryService.getById(supplierOrderId);
                Asserts.isTrue(ObjectUtils.equalsAny(tradeSupplierOrderDO.getOrderStatus(),TradeOrderStatusEnum.UNPAID.getStatus(), TradeOrderStatusEnum.PROCESS_FAIL.getStatus()),"供应商订单状态已变更，不能重试{}",tradeSupplierOrderDO.getOrderStatus());
                //添加重试记录
                SupplierRetryRecordDO supplierRetryRecordDO = tradeSupplierOrderRepositoryService.addRetryRecord(supplierOrderId,SUPPLIER_RETRY_TYPE_PAY);
                List<TradeSupplierOrderDO> tradeSupplierOrderDOList = new ArrayList<>();
                tradeSupplierOrderDOList.add(tradeSupplierOrderDO);

                TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(tradeSupplierOrderDO.getOrderId());

                CommonResult<?> resp =  payOrderFromSupplierSystem(tradeSupplierOrderDOList,tradeOrderDO);
                supplierRetryRecordDO.setReturnMsg(JSONUtil.toJsonStr(resp));

                if(resp.isSuccess()){
                    supplierRetryRecordDO.setStatus(SUCCESS);
                }else{
                    supplierRetryRecordDO.setStatus(FAIL);
                }
                tradeSupplierOrderRepositoryService.updateRetryRecord(supplierRetryRecordDO);
                return resp;
            }
        }catch (ServiceException e){
            ExceptionUtils.log(log,"供应商重试退款修改退款批次异常refundId:"+supplierOrderId,e);
            return CommonResult.error(e);
        }catch (Exception e){
            log.error("供应商重试出票异常supplierOrderId:"+supplierOrderId,e);
        } finally {
            if(lock.isLocked() && lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
        return CommonResult.error(SUPPLIER_PAY_RETRY_EXCEPTION);
    }

    /**
     * 处理供应商的退款审核通知结果
     * @param refundAuditNotifyBO
     * @return
     */
    @Override
    public CommonResult<?> handleRefundAuditNotify(RefundAuditNotifyBO refundAuditNotifyBO){
        Long supplierRefundId = refundAuditNotifyBO.getRefundId();
        String lockKey = String.format(UPDATE_REFUND_SUPPLIER_LOCK,supplierRefundId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                //更新供应商退款单状态,审核中-》退款失败 or 退款成功
                SupplierRefundDO supplierRefundDO = tradeSupplierOrderRepositoryService.getSupplierRefundById(refundAuditNotifyBO.getRefundId());
                Asserts.isTrue(ObjectUtil.equal(supplierRefundDO.getRefundStatus(),RefundStatusEnum.AUDITING.getStatus()),"供应商退款单状态已变更不能修改{}",supplierRefundDO.getRefundStatus());
                CommonResult<SupplierRefundRespBO> resp;
                if(refundAuditNotifyBO.getAuditResult() == NO){
                    resp = CommonResult.error(SUPPLIER_REFUND_AUDIT_REFUSE);
                    tradeSupplierCallbackService.afterRefundFail(resp,supplierRefundDO);
                    CommonResult<Object> error = CommonResult.error(SUPPLIER_REFUND_AUDIT_REFUSE);
                    error.setData(supplierRefundDO.getRefundId());
                    return error;
                }else {
                    SupplierRefundRespBO supplierRefundRespBO = new SupplierRefundRespBO();
                    supplierRefundRespBO.setSupplierRefundNo(refundAuditNotifyBO.getSupplierRefundNo());
                    resp = CommonResult.success(supplierRefundRespBO);
                    //退款成功，更新供应商订单状态
                    tradeSupplierCallbackService.afterRefundSuccess(resp.getData(),supplierRefundDO);
                    //修改原供应商订单订单状态
                    updateSupplierOrderStatusAfterRefund(supplierRefundDO);
                    return CommonResult.success(supplierRefundDO.getRefundId());
                }
            }
        }catch (ServiceException e){
            ExceptionUtils.log(log,"供应商退款单修改异常:"+supplierRefundId,e);
            return CommonResult.error(e);
        }catch (Exception e){
            log.error("供应商退款单修改异常"+supplierRefundId,e);
        } finally {
            if(lock.isLocked() && lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
        return CommonResult.error(SUPPLIER_HANDLE_REFUND_AUDIT_EXCEPTION);
    }

    @Override
    public CommonResult<?> bindVisitor(Long orderId,List<TradeVisitorDO> tradeVisitorDOList) {
        //查询订单下的供应商订单
        List<TradeSupplierOrderDO> tradeSupplierOrderDOList = tradeSupplierOrderRepositoryService.getTradeSupplierOrderList(orderId);
        List<Long> visitorIdList = tradeVisitorDOList.stream().map(TradeVisitorDO::getId).collect(Collectors.toList());
        boolean flag = true;
        for (TradeSupplierOrderDO tradeSupplierOrderDO : tradeSupplierOrderDOList) {
            //获取供应商需要补录的游客
            List<TradeVisitorBO> tradeVisitorBOList = tradeSupplierOrderRepositoryService.getSupplierVisitor(tradeSupplierOrderDO.getId(),visitorIdList);
            if(tradeVisitorBOList.isEmpty()){
                continue;
            }
            CommonResult<?> commonResult = bindVisitorFromSupplierSystem(tradeSupplierOrderDO,tradeVisitorBOList);
            if(commonResult.isError()){
                flag = false;
            }
        }
        return flag?CommonResult.success(null):CommonResult.error(SUPPLIER_BIND_VISITOR_FAIL);
    }

    @Override
    public CommonResult<?> cancelOrder(TradeOrderDO tradeOrderDO,Boolean isManual) {
        List<TradeSupplierOrderDO> tradeSupplierOrderDOList = tradeSupplierOrderRepositoryService.getTradeSupplierOrderList(tradeOrderDO.getId());
        CommonResult<?> resp = CommonResult.success(null);
        if(!isManual){
            //系统自动取消，则由平台自己自动取消
            tradeSupplierOrderDOList = tradeSupplierOrderDOList.stream().filter(item->ObjectUtil.notEqual(item.getSupplierType(),SUPPLIER_TYPE_PLAT)).collect(Collectors.toList());
        }
        if(CollectionUtil.isNotEmpty(tradeSupplierOrderDOList)){
            //3.向供应商分别取消订单
            try{
                tradeSupplierOrderDOList.forEach(tradeSupplierOrderDO -> {
                    getSelf().doCancelOrderFromSupplierSystem(tradeSupplierOrderDO,tradeOrderDO);
                });
            }catch (ServiceException e){
                ExceptionUtils.log(log,"调用供应商服务取消订单失败:",e);
                return CommonResult.error(e);
            }catch (Exception e){
                log.error("调用供应商服务取消订单失败：",e);
                return CommonResult.error(SUPPLIER_SERVICE_ORDER_PAY_FAIL);
            }
        }

        return resp;
    }

    private List<TradeSupplierOrderBO> buildSupplierOrder(TradeOrderBO tradeOrderBO){

        List<TradeOrderDetailBaseBO> needSupplierOrderList = tradeSupplierOrderRepositoryService.getNeedSupplierOrderList(tradeOrderBO.getTradeOrderDO().getId());
        return buildTradeSupplierOrder(needSupplierOrderList,tradeOrderBO);
    }

    private List<TradeSupplierOrderBO> buildTradeSupplierOrder(List<TradeOrderDetailBaseBO> needSupplierOrderList,TradeOrderBO tradeOrderBO){
        if(CollectionUtil.isEmpty(needSupplierOrderList)){
            return ListUtil.empty();
        }
        List<TradeSupplierOrderBO> tradeSupplierOrderBOList = new ArrayList<>();
        needSupplierOrderList.forEach(tradeOrderDetailBaseBO -> {
            TradeSupplierOrderBO tradeSupplierOrderBO = new TradeSupplierOrderBO();
            tradeSupplierOrderBO.setRemark(tradeOrderBO.getTradeOrderDO().getRemark());
            tradeSupplierOrderBO.setRoutePlanId(tradeOrderDetailBaseBO.getRoutePlanId());
            tradeSupplierOrderBO.setIsMarketing(tradeOrderBO.getTradeOrderDO().getIsMarketing());
            tradeSupplierOrderBO.setIsMarketingUse(tradeOrderBO.getTradeOrderDO().getIsMarketingUse());
            if(ObjectUtil.equal(tradeOrderBO.getExtraInfo().getIsChange(),YES)){
                //查找对应的供应商订单，用于改签
                TradeSupplierOrderDO tradeSupplierOrderDO = tradeSupplierOrderRepositoryService.getSupplierOrderByChange(tradeOrderBO.getExtraInfo().getMainOrderId(),tradeOrderDetailBaseBO.getSupplierProductId(),tradeOrderDetailBaseBO.getSupplierId());
                if(tradeSupplierOrderDO != null){
                    tradeSupplierOrderBO.setIsChange(tradeOrderBO.getExtraInfo().getIsChange());
                    tradeSupplierOrderBO.setMainOrderNo(tradeSupplierOrderDO.getSupplierOrderNo());
                }
            }
            if(ObjectUtil.equal(tradeOrderBO.getTradeOrderDO().getIsAddOrder(),YES)){
                //查找对应的供应商订单，用于增加
                TradeSupplierOrderDO tradeSupplierOrderDO = tradeSupplierOrderRepositoryService.getSupplierOrderByChange(tradeOrderBO.getExtraInfo().getMainOrderId(),tradeOrderDetailBaseBO.getSupplierProductId(),tradeOrderDetailBaseBO.getSupplierId());
                if(tradeSupplierOrderDO != null){
                    tradeSupplierOrderBO.setIsAddOrder(YES.getType());
                    tradeSupplierOrderBO.setMainOrderNo(tradeSupplierOrderDO.getSupplierOrderNo());
                }
            }
            tradeSupplierOrderBO.setIsTimePay(tradeOrderBO.getExtraInfo().getIsTimePay());
            tradeSupplierOrderBO.setStoreId(tradeOrderBO.getTradeOrderDO().getStoreId());
            tradeSupplierOrderBO.setStoreName(tradeOrderBO.getTradeOrderDO().getStoreName());
            tradeSupplierOrderBO.setAgencyGroupId(tradeOrderBO.getTradeOrderDO().getAgencyGroupId());
            tradeSupplierOrderBO.setAreaManagerId(tradeOrderBO.getTradeOrderDO().getAreaManagerId());
            tradeSupplierOrderBO.setOrderNo(tradeOrderBO.getTradeOrderDO().getOrderNo());
            tradeSupplierOrderBO.setTradeOrderDeliveryDO(tradeOrderBO.getTradeOrderDeliveryDO());

            //供应商订单
            TradeSupplierOrderDO tradeSupplierOrderDO = new TradeSupplierOrderDO();
            tradeSupplierOrderDO.setId(IdWorker.getId());
            tradeSupplierOrderDO.setTradeNo(tradeUUCodeUtils.generateOrderNo(SUPPLIER_ORDER_PREFIX));
            tradeSupplierOrderDO.setOrderId(tradeOrderBO.getTradeOrderDO().getId());
            tradeSupplierOrderDO.setOrderStatus(TradeOrderStatusEnum.INIT.getStatus());

            List<TradeDetailBaseDO> baseDOList;
            if(tradeOrderDetailBaseBO.getProductBaseType() == PRODUCT_BASE_TYPE_PLAT){
                tradeSupplierOrderDO.setSupplierType(SUPPLIER_TYPE_PLAT);
            }else{
                tradeSupplierOrderDO.setSupplierType(SUPPLIER_TYPE_OTHER);
                tradeSupplierOrderDO.setProductBaseId(tradeOrderDetailBaseBO.getProductBaseId());
            }

            if(tradeOrderDetailBaseBO.getHotelOrderId() != null){
                TradeOrderDetailBO tradeOrderDetailBO = tradeOrderBO.getTradeOrderDetailBOList().stream().filter(detailBO -> {
                    return ObjectUtil.equal(detailBO.getTradeOrderHotelDO().getId(), tradeOrderDetailBaseBO.getHotelOrderId());
                }).findFirst().orElse(null);
                Asserts.isTrue(tradeOrderDetailBO!=null,"供应商订单未找到酒店信息");
                tradeSupplierOrderBO.setTradeOrderHotelDO(tradeOrderDetailBO.getTradeOrderHotelDO());
            }
            baseDOList = tradeSupplierOrderRepositoryService.getBaseListFromOrder(tradeOrderBO.getTradeOrderDO().getId(),tradeOrderDetailBaseBO);
            tradeSupplierOrderDO.setSupplierId(tradeOrderDetailBaseBO.getSupplierId());
            tradeSupplierOrderDO.setSupplierName(tradeOrderDetailBaseBO.getSupplierName());
            tradeSupplierOrderDO.setSupplierProductId(tradeOrderDetailBaseBO.getSupplierProductId());
            tradeSupplierOrderDO.setQuantity(tradeOrderDetailBaseBO.getQuantity());
            tradeSupplierOrderDO.setAmount(tradeOrderDetailBaseBO.getAmount());
            tradeSupplierOrderDO.setQuantityOfOne(tradeOrderDetailBaseBO.getQuantityOfOne());
            tradeSupplierOrderDO.setUseRealName(tradeOrderDetailBaseBO.getUseRealName());
            tradeSupplierOrderDO.setUseDate(tradeOrderDetailBaseBO.getUseDate());
            tradeSupplierOrderBO.setTradeSupplierOrderDO(tradeSupplierOrderDO);
            tradeSupplierOrderBO.setTradeDetailBaseDOList(baseDOList);
            tradeSupplierOrderBOList.add(tradeSupplierOrderBO);
        });

        return tradeSupplierOrderBOList;
    }


    private CommonResult<TradeSupplierOrderRespBO> createOrderFromSupplierSystem( List<TradeSupplierOrderBO> tradeSupplierOrderBOList ){
        try{
            for (TradeSupplierOrderBO tradeSupplierOrderBO : tradeSupplierOrderBOList) {

                getSelf().doCreateOrderFromSupplierSystem(tradeSupplierOrderBO);
            }
        }catch (ServiceException e){
            ExceptionUtils.log(log,"调用供应商服务下单失败:",e);
            return CommonResult.error(e);
        }catch (Exception e){
            log.error("调用供应商服务下单失败：",e);
            return CommonResult.error(SUPPLIER_SERVICE_ORDER_CREATE_FAIL);
        }
        //全部下单完成
        return CommonResult.success(null);
    }

    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SUPPLIER_ORDER_CREATE)
    public void doCreateOrderFromSupplierSystem(TradeSupplierOrderBO tradeSupplierOrderBO){
        SupplierTradeService supplierTradeService;
        SupplierRespDTO supplierRespDTO = null;
        MapBuilder<String,Object> logContentBuilder =  MapUtil.builder();
//        if(tradeSupplierOrderBO.getTradeSupplierOrderDO().getSupplierType() == SUPPLIER_TYPE_PLAT){
//            //平台分销订单
//            supplierTradeService = allSupplierTradeService.get(PLAT_SERVICE);
//            logContentBuilder.put("supplierName","平台" ).put("serviceName",PLAT_SERVICE);
//        }else {
            supplierRespDTO = resourceApi.getSupplierById(tradeSupplierOrderBO.getTradeSupplierOrderDO().getSupplierId()).getCheckedData();
            supplierTradeService = allSupplierTradeService.get(supplierRespDTO.getDirectServer());
            Asserts.isTrue(supplierTradeService!=null,"未找到对应供应商实现类：{}",supplierRespDTO.getDirectServer());
            logContentBuilder.put("supplierName",supplierRespDTO.getName() ).put("serviceName",supplierRespDTO.getDirectServer());
//        }

        SupplierTradeOrderBO supplierTradeOrderBO = new SupplierTradeOrderBO();
        supplierTradeOrderBO.setTradeSupplierOrderDO(tradeSupplierOrderBO.getTradeSupplierOrderDO());
        supplierTradeOrderBO.setRemark(tradeSupplierOrderBO.getRemark());
        supplierTradeOrderBO.setRoutePlanId(tradeSupplierOrderBO.getRoutePlanId());
        supplierTradeOrderBO.setIsMarketing(tradeSupplierOrderBO.getIsMarketing());
        supplierTradeOrderBO.setIsMarketingUse(tradeSupplierOrderBO.getIsMarketingUse());
        supplierTradeOrderBO.setIsChange(tradeSupplierOrderBO.getIsChange());
        supplierTradeOrderBO.setIsTimePay(tradeSupplierOrderBO.getIsTimePay());
        supplierTradeOrderBO.setMainOrderNo(tradeSupplierOrderBO.getMainOrderNo());
        supplierTradeOrderBO.setStoreId(tradeSupplierOrderBO.getStoreId());
        supplierTradeOrderBO.setStoreName(tradeSupplierOrderBO.getStoreName());
        supplierTradeOrderBO.setAgencyGroupId(tradeSupplierOrderBO.getAgencyGroupId());
        supplierTradeOrderBO.setAreaManagerId(tradeSupplierOrderBO.getAreaManagerId());
        supplierTradeOrderBO.setIsAddOrder(tradeSupplierOrderBO.getIsAddOrder());
        supplierTradeOrderBO.setOrderNo(tradeSupplierOrderBO.getOrderNo());
        supplierTradeOrderBO.setTradeOrderDeliveryDO(tradeSupplierOrderBO.getTradeOrderDeliveryDO());
        supplierTradeOrderBO.setTradeOrderHotelDO(tradeSupplierOrderBO.getTradeOrderHotelDO());

        //获取对应游客信息
        List<TradeVisitorDO> tradeVisitorDOList = tradeSupplierOrderRepositoryService.getVisitorListBySupplierOrder(tradeSupplierOrderBO.getTradeSupplierOrderDO().getId());
        if(tradeSupplierOrderBO.getTradeSupplierOrderDO().getQuantityOfOne() !=null && tradeSupplierOrderBO.getTradeSupplierOrderDO().getQuantityOfOne() > 1){
            //处理一票多人情况
            Map<Long,List<TradeVisitorDO>> groupMap = tradeVisitorDOList.stream().collect(Collectors.groupingBy(TradeVisitorDO::getDetailId));
            List<MutilTradeVisitorBO> mutilTradeVisitorBOList = groupMap.values().stream().map(list->{
                MutilTradeVisitorBO mutilTradeVisitorBO = new MutilTradeVisitorBO();
                mutilTradeVisitorBO.setTradeVisitorList(list);
                return mutilTradeVisitorBO;
            }).collect(Collectors.toList());
            supplierTradeOrderBO.setMultilVisitorList(mutilTradeVisitorBOList);
        }else{
            supplierTradeOrderBO.setTradeVisitorDOList(tradeVisitorDOList);
        }

        CommonResult<SupplierTradeOrderRespBO> resp = supplierTradeService.createOrder(supplierTradeOrderBO,supplierRespDTO);
        //设置供应商下单日志参数
        TradeOrderLogUtils.setOrderInfo(tradeSupplierOrderBO.getTradeSupplierOrderDO().getOrderId(),null,null,logContentBuilder.put("result",resp.isSuccess()?"成功":"失败")
                .put("platSupplierOrderId",tradeSupplierOrderBO.getTradeSupplierOrderDO().getId()).build());

        Assert.isTrue(resp.isSuccess(),()->{
            //下单失败
            tradeSupplierCallbackService.afterOrderCreateFail(tradeSupplierOrderBO);
            return exception(new ErrorCode(resp.getCode(),resp.getMsg()));
        });
        //下单成功，更新供应商订单状态
        tradeSupplierCallbackService.afterOrderCreate(resp.getData(),tradeSupplierOrderBO);
    }

    private CommonResult<?> payOrderFromSupplierSystem(List<TradeSupplierOrderDO> tradeSupplierOrderDOList,TradeOrderDO tradeOrderDO){
        try{
            tradeSupplierOrderDOList.forEach(tradeSupplierOrderDO -> {
                getSelf().doPayOrderFromSupplierSystem(tradeSupplierOrderDO,tradeOrderDO);
            });
        }catch (ServiceException e){
            ExceptionUtils.log(log,"调用供应商服务支付出票失败:",e);
            return CommonResult.error(e);
        }catch (Exception e){
            log.error("调用供应商服务支付出票失败：",e);
            return CommonResult.error(SUPPLIER_SERVICE_ORDER_PAY_FAIL);
        }

        return  CommonResult.success(null);
    }

    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SUPPLIER_ORDER_PAY)
    public void doPayOrderFromSupplierSystem(TradeSupplierOrderDO tradeSupplierOrderDO,TradeOrderDO tradeOrderDO){
        SupplierTradeService supplierTradeService;
        SupplierRespDTO supplierRespDTO =null;
        MapBuilder<String,Object> logContentBuilder =  MapUtil.builder();
        if(tradeSupplierOrderDO.getSupplierType() == SUPPLIER_TYPE_PLAT){
            //平台分销订单
            supplierTradeService = allSupplierTradeService.get(PLAT_SERVICE);
            logContentBuilder.put("supplierName","平台" );
        }else {
            //获取分销商服务类
            supplierRespDTO = resourceApi.getSupplierById(tradeSupplierOrderDO.getSupplierId()).getCheckedData();
            supplierTradeService = allSupplierTradeService.get(supplierRespDTO.getDirectServer());
            Asserts.isTrue(supplierTradeService!=null,"未找到对应供应商实现类：{}",supplierRespDTO.getDirectServer());
            logContentBuilder.put("supplierName",supplierRespDTO.getName() );
        }
        //更新供应商订单为出票中
        tradeSupplierCallbackService.beforeOrderPay(tradeSupplierOrderDO);

        SupplierTradeOrderPayBO supplierTradeOrderPayBO = new SupplierTradeOrderPayBO();
        supplierTradeOrderPayBO.setTradeSupplierOrderDO(tradeSupplierOrderDO);
        supplierTradeOrderPayBO.setTradeOrderDO(tradeOrderDO);
        CommonResult<SupplierTradeOrderPayRespBO> resp = supplierTradeService.payOrder(supplierTradeOrderPayBO,supplierRespDTO);
        //设置供应商下单日志参数
        TradeOrderLogUtils.setOrderInfo(tradeSupplierOrderDO.getOrderId(),TradeOrderStatusEnum.PAID.getStatus(), null,logContentBuilder.put("result",resp.isSuccess()?"成功":"失败")
                .put("platSupplierOrderId",tradeSupplierOrderDO.getId()).build());

        Assert.isTrue(resp.isSuccess(),()->{
            //支付失败
            tradeSupplierCallbackService.afterOrderPayFail(tradeSupplierOrderDO);
            return exception(new ErrorCode(resp.getCode(),resp.getMsg()));
        });

        //验证券码数量并去重
        voucherCheckAndDistinct(resp.getData(),tradeSupplierOrderDO);

        //出票成功，更新供应商订单状态
        tradeSupplierCallbackService.afterOrderPaySuccess(resp.getData(),tradeSupplierOrderDO);
    }

    private CommonResult<?> refundFromSupplierSystem(List<SupplierRefundDO> supplierRefundDOList ){

        int refundStatus = RefundStatusEnum.REFUND.getStatus();
        for (SupplierRefundDO supplierRefundDO : supplierRefundDOList) {

            getSelf().doRefundFromSupplierSystem(supplierRefundDO);

            if(ObjectUtil.equal(supplierRefundDO.getRefundStatus(),RefundStatusEnum.REFUND_FAIL.getStatus())){
                //有失败的则整体供应商退款就是失败
                refundStatus = RefundStatusEnum.REFUND_FAIL.getStatus();
            }else if(ObjectUtil.equal(supplierRefundDO.getRefundStatus(),RefundStatusEnum.AUDITING.getStatus()) && refundStatus!=RefundStatusEnum.REFUND_FAIL.getStatus()){
                //没有退款失败，但有退款中的则为退款中
                refundStatus = RefundStatusEnum.AUDITING.getStatus();
            }
        }

        if(refundStatus == RefundStatusEnum.REFUND.getStatus()){
            return CommonResult.success(null);
        }else if(refundStatus == RefundStatusEnum.AUDITING.getStatus()){
            return CommonResult.error(REFUND_AUDITING);
        }else{
            return CommonResult.error(SUPPLIER_SERVICE_REFUND_CONFIRM);
        }
    }

    /**
     *
     * @param supplierRefundDO
     */
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SUPPLIER_ORDER_REFUND)
    public void doRefundFromSupplierSystem(SupplierRefundDO supplierRefundDO){
        try{
            SupplierTradeService supplierTradeService;
            SupplierRespDTO supplierRespDTO = null;
            MapBuilder<String,Object> logContentBuilder =  MapUtil.builder();
            if(supplierRefundDO.getSupplierType() == SUPPLIER_TYPE_PLAT){
                //平台分销订单
                supplierTradeService = allSupplierTradeService.get(PLAT_SERVICE);
                logContentBuilder.put("supplierName","平台" );
            }else {
                //获取分销商服务类
                supplierRespDTO = resourceApi.getSupplierById(supplierRefundDO.getSupplierId()).getCheckedData();
                supplierTradeService = allSupplierTradeService.get(supplierRespDTO.getDirectServer());
                Asserts.isTrue(supplierTradeService!=null,"未找到对应供应商实现类：{}",supplierRespDTO.getDirectServer());
                logContentBuilder.put("supplierName",supplierRespDTO.getName() );
            }

            CommonResult<SupplierRefundRespBO> resp = supplierTradeService.refund(supplierRefundDO,supplierRespDTO);
            //设置供应商下单日志参数
            TradeOrderLogUtils.setOrderInfo(supplierRefundDO.getOrderId(),TradeOrderStatusEnum.REFUNDING.getStatus(), null,logContentBuilder.put("result",resp.isSuccess()?"成功":"失败")
                    .put("refundId",supplierRefundDO.getRefundId()).put("platSupplierRefundId",supplierRefundDO.getId()).build());
            //如果退款失败，后续退款继续，失败请求人工处理或者系统重试
            if(resp.isError()){
                tradeSupplierCallbackService.afterRefundFail(resp,supplierRefundDO);
            }else {
                //退款成功，更新供应商订单状态
                tradeSupplierCallbackService.afterRefundSuccess(resp.getData(),supplierRefundDO);
                //修改原供应商订单订单状态
                updateSupplierOrderStatusAfterRefund(supplierRefundDO);
            }

        }catch (Exception e){
            log.error("调用供应商服务退款失败：",e);
        }
    }

    private void voucherCheckAndDistinct(SupplierTradeOrderPayRespBO respBO, TradeSupplierOrderDO tradeSupplierOrderDO){
        List<OtaVoucherVO> voucherVOList = respBO.getVoucherList();
        if(tradeSupplierOrderDO.getQuantityOfOne() > 1){
            //一票多人，根据券码去重
            voucherVOList = respBO.getVoucherList().stream().collect(
                    collectingAndThen(toCollection(()-> new TreeSet<>(Comparator.comparing(OtaVoucherVO::getVoucherCode)))
                            , ArrayList::new));

            respBO.setVoucherList(voucherVOList);
        }
        Assert.isTrue(ObjectUtil.equal(voucherVOList.size(),tradeSupplierOrderDO.getQuantity()),()->{
            //支付失败
            tradeSupplierCallbackService.afterOrderPayFail(tradeSupplierOrderDO);
            return exception(SUPPLIER_SERVICE_ORDER_VOUCHER);
        });
    }

    private void createSupplierRefundOrder(TradeRefundBO tradeRefundBO, List<SupplierRefundDO> supplierRefundList){
        RefundDO refundDO = tradeRefundBO.getRefundDO();
        for (SupplierRefundDO supplierRefundDO : supplierRefundList) {
            supplierRefundDO.setId(IdWorker.getId());
            supplierRefundDO.setRefundStatus(RefundStatusEnum.INIT.getStatus());
            supplierRefundDO.setRefundMethod(refundDO.getRefundMethod());
            supplierRefundDO.setIgnorePlatRefund(tradeRefundBO.isIgnorePlatRefund()?YES.getType():NO);
        }
        //保存供应商退款单
        tradeSupplierOrderRepositoryService.saveSupplierRefundOrder(supplierRefundList);
        //关联退款明细基础
        tradeSupplierOrderRepositoryService.updateSupplierRefundDetailBase(supplierRefundList);
        //更新退款批次供应商状态
        refundDO.setSupplierRefundStatus(RefundStatusEnum.INIT.getStatus());
        tradeRefundRepositoryService.updateRefundSupplierStatus(refundDO.getId(),RefundStatusEnum.INIT);

    }

    private void updateSupplierOrderStatusAfterRefund(SupplierRefundDO supplierRefundDO){
        String lockKey = String.format(UPDATE_SUPPLIER_ORDER_LOCK,supplierRefundDO.getPlatSupplierOrderId());
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                TradeSupplierOrderDO tradeSupplierOrderDO = tradeSupplierOrderRepositoryService.getById(supplierRefundDO.getPlatSupplierOrderId());
                Map<String,Long> data = tradeRefundRepositoryService.getSupplierRefundCountBySupplierOrderId(supplierRefundDO.getPlatSupplierOrderId());
                if(ObjectUtil.equal(data.get("quantity"),data.get("refundCount").intValue())){
                    tradeSupplierOrderDO.setOrderStatus(TradeOrderStatusEnum.ALL_REFUND.getStatus());
                }else{
                    tradeSupplierOrderDO.setOrderStatus(TradeOrderStatusEnum.PARTIAL_REFUND.getStatus());
                }
                tradeSupplierOrderRepositoryService.updateOrderStatus(tradeSupplierOrderDO);
            }
        }catch (Exception e){
            log.error("供应商退款后修改供应商订单状态异常:"+supplierRefundDO.getId(),e);
        } finally {
            if(lock.isLocked() && lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
    }

    private  CommonResult<?> bindVisitorFromSupplierSystem(TradeSupplierOrderDO tradeSupplierOrderDO, List<TradeVisitorBO> tradeVisitorBOList ){
        try {
            SupplierTradeService supplierTradeService;
            if(tradeSupplierOrderDO.getSupplierType() == SUPPLIER_TYPE_PLAT){
                //平台分销订单
                supplierTradeService = allSupplierTradeService.get(PLAT_SERVICE);
            }else {
                return CommonResult.error(SUPPLIER_NOT_SUPPORT_BIND_VISITOR);
            }
            SupplierTradeBindVisitorBO supplierTradeBindVisitorBO = new SupplierTradeBindVisitorBO();
            supplierTradeBindVisitorBO.setBindItemList(convert(tradeVisitorBOList));
            supplierTradeBindVisitorBO.setTradeSupplierOrderDO(tradeSupplierOrderDO);
            return supplierTradeService.bindVisitor(supplierTradeBindVisitorBO,null);
        }catch (Exception e){
            log.error("调用供应商服务补录失败：",e);
        }
        return CommonResult.error(UNKNOWN_EXCEPTION);
    }

    private List<TradeBindVisitorReqDTO.BindItem> convert(List<TradeVisitorBO> tradeVisitorBOList){
        //根据供应商票号分组
        Map<String,List<TradeVisitorBO>> groupMap = tradeVisitorBOList.stream().collect(Collectors.groupingBy(TradeVisitorBO::getSupplierVoucherCode));
        List<TradeBindVisitorReqDTO.BindItem> bindItemList = groupMap.entrySet().stream().map(groupItem->{
            TradeBindVisitorReqDTO.BindItem bindItem = new TradeBindVisitorReqDTO.BindItem();
            List<TradeOrderCreateReqDTO.Visitor> visitorList = TradeOrderConvert.INSTANCE.convertToList(groupItem.getValue());
            bindItem.setVoucherCode(groupItem.getKey());
            bindItem.setVisitorList(visitorList);
            return bindItem;
        }).collect(Collectors.toList());
        return bindItemList;
    }

    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SUPPLIER_ORDER_CANCEL)
    public void doCancelOrderFromSupplierSystem(TradeSupplierOrderDO tradeSupplierOrderDO,TradeOrderDO tradeOrderDO){
        SupplierTradeService supplierTradeService;
        SupplierRespDTO supplierRespDTO =null;
        MapBuilder<String,Object> logContentBuilder =  MapUtil.builder();
        if(tradeSupplierOrderDO.getSupplierType() == SUPPLIER_TYPE_PLAT){
            //平台分销订单
            supplierTradeService = allSupplierTradeService.get(PLAT_SERVICE);
            logContentBuilder.put("supplierName","平台" );
        }else {
            //获取分销商服务类
            supplierRespDTO = resourceApi.getSupplierById(tradeSupplierOrderDO.getSupplierId()).getCheckedData();
            supplierTradeService = allSupplierTradeService.get(supplierRespDTO.getDirectServer());
            Asserts.isTrue(supplierTradeService!=null,"未找到对应供应商实现类：{}",supplierRespDTO.getDirectServer());
            logContentBuilder.put("supplierName",supplierRespDTO.getName() );
        }

        CommonResult<?> resp = supplierTradeService.cancelOrder(tradeSupplierOrderDO.getSupplierOrderNo(),supplierRespDTO);
        //设置供应商下单日志参数
        TradeOrderLogUtils.setOrderInfo(tradeSupplierOrderDO.getOrderId(),tradeOrderDO.getOrderStatus(), null,logContentBuilder.put("result",resp.isSuccess()?"成功":"失败")
                .put("platSupplierOrderId",tradeSupplierOrderDO.getId()).build());

        if(resp.isSuccess()){
            tradeSupplierOrderDO.setOrderStatus(TradeOrderStatusEnum.CANCELED.getStatus());
            tradeSupplierOrderRepositoryService.updateOrderStatus(tradeSupplierOrderDO);
        }
    }

    @Override
    public void mergeSupplierOrder(Long addOrderId, Long mainOrderId){
        //供应商订单
        List<TradeSupplierOrderDO> tradeSupplierOrderList = tradeSupplierOrderRepositoryService.getTradeSupplierOrderList(addOrderId);
        List<TradeSupplierOrderDO> mainSupplierOrderList = tradeSupplierOrderRepositoryService.getTradeSupplierOrderList(mainOrderId);
        //供应商订单明细
        for (TradeSupplierOrderDO tradeSupplierOrderDO : tradeSupplierOrderList) {
            TradeSupplierOrderDO mainSupplierOrder = mainSupplierOrderList.stream().filter(supplierOrder -> ObjectUtil.equal(tradeSupplierOrderDO.getSupplierProductId(), supplierOrder.getSupplierProductId())
                    && ObjectUtil.equal(tradeSupplierOrderDO.getSupplierId(), supplierOrder.getSupplierId())).findFirst().orElse(null);
            if(mainSupplierOrder == null){
                continue;
            }
            tradeSupplierOrderRepositoryService.updateAddSupplierOrder(tradeSupplierOrderDO,mainSupplierOrder);
        }
    }

    private TradeSupplierServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }
}
