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


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.DateUtils;
import com.yc.ship.framework.common.exception.ServerException;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.collection.CollectionUtils;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.ota.api.OtaDistributorApi;
import com.yc.ship.module.ota.api.dto.DistributorProductRespDTO;
import com.yc.ship.module.ota.api.dto.DistributorRespDTO;
import com.yc.ship.module.product.api.ProductApi;
import com.yc.ship.module.product.api.dto.ProductSaleRuleRespDTO;
import com.yc.ship.module.product.api.dto.ProductSpuRespDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderCreateReqDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderRespDTO;
import com.yc.ship.module.trade.api.dto.TradeRefundCreateReqDTO;
import com.yc.ship.module.trade.api.dto.TradeRefundRespDTO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.PayOrderReqVO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.PayOrderRespVO;
import com.yc.ship.module.trade.convert.order.TradeRefundConvert;
import com.yc.ship.module.trade.convert.ota.OtaConvert;
import com.yc.ship.module.trade.dal.dataobject.order.TradeDetailDO;
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.enums.PayAccountTypeEnum;
import com.yc.ship.module.trade.enums.PayTypeEnum;
import com.yc.ship.module.trade.enums.RefundStatusEnum;
import com.yc.ship.module.trade.enums.TradeOrderStatusEnum;
import com.yc.ship.module.trade.enums.ota.OtaConstants;
import com.yc.ship.module.trade.framework.common.ota.TongChengAuthUtil;
import com.yc.ship.module.trade.framework.common.ota.TongChengResponse;
import com.yc.ship.module.trade.service.notifylog.NotifyLogService;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.service.order.TradeOrderRuleValidate;
import com.yc.ship.module.trade.service.order.TradeOrderService;
import com.yc.ship.module.trade.service.ota.OtaService;
import com.yc.ship.module.trade.service.ota.TongChengService;
import com.yc.ship.module.trade.service.pay.TradeOrderPayService;
import com.yc.ship.module.trade.service.refund.TradeRefundRepositoryService;
import com.yc.ship.module.trade.service.refund.TradeRefundService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.*;
import static com.yc.ship.module.trade.enums.TravelhubDictTypeConstants.PRODUCT_BASE_TYPE_SELF;
import static com.yc.ship.module.trade.enums.ota.OtaConstants.*;
import static com.yc.ship.module.trade.service.ota.OtaService.tongCheng;

/**
 * 同程
 */
@Service(tongCheng)
@Slf4j
public class TongChengServiceImpl implements TongChengService, OtaService {

    @Resource
    private OtaDistributorApi otaDistributorApi;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ProductApi productApi;
    @Resource
    private TradeOrderService tradeOrderService;
    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;
    @Resource
    private ConfigApi configApi;
    @Resource
    private TradeOrderPayService tradeOrderPayService;
    @Resource
    private NotifyLogService notifyLogService;
    @Resource
    private TradeRefundService tradeRefundService;

    @Resource
    private TradeRefundRepositoryService tradeRefundRepositoryService;


    /**
     * 同程-请求
     * （包含非实名制：非实名制，游客信息为空）
     */
    @Override
    public String doRequest(Long tenantId, String path, HttpServletRequest request, String jsonStr) {
        Map<String, Object> resultMap = new HashMap<String, Object>(0);
        try {
            TenantContextHolder.setTenantId(tenantId);
            TenantContextHolder.setIgnore(false);
            //获取分销商信息
            DistributorRespDTO distributor = otaDistributorApi.getDistributorByOtaAccount("", OtaConstants.OTA_TONG_CHENG_TYPECODE).getCheckedData();

            if (distributor == null) {
                resultMap.put(OTA_STATUS, OTA_SIGN_FAIL);
                resultMap.put(MSG, "sign或帐号校验失败");
                return resultMap.toString();
            }

            String key = "[ota-in]" + distributor.getId();
            RLock lock = redissonClient.getLock(key);
            try {
                if (lock.tryLock(30, TimeUnit.SECONDS)) {
                    try {
                        //一、签名校验
                        // base64解密
                        Map<String, String> requestMap = TongChengAuthUtil.decodeRequestJson(jsonStr, distributor.getSecret());
                        // 请求头requestHead
                        JSONObject requestHead = JSONUtil.parseObj(requestMap.get("requestHead"));
                        // 内容体requestBody
                        JSONObject body = JSONUtil.parseObj(requestMap.get("requestBody"));
                        log.info("同程请求Head:" + requestHead.toString() + " Body:" + body.toString());
                        if (TongChengAuthUtil.checkSign(TongChengAuthUtil.parseRequestHead(requestHead),
                                distributor.getAppid(), distributor.getSecret(), requestMap.get("requestBodyNotDe")) && TongChengAuthUtil.checkAccount(requestHead, distributor.getAppid())) {
                            log.info("校验成功.");
                        } else {
                            log.info("校验失败.");
                            resultMap.put(OTA_STATUS, OTA_SIGN_FAIL);
                            resultMap.put(MSG, "sign或帐号校验失败");
                            return resultMap.toString();
                        }
                        String method = requestHead.getStr("method");
                        if ("GetProductInfo".equals(method)) {
                            return getProductInfo(body, distributor);
                            // 同程下单验证接口对接
                        } else if ("CreateOrderValidate".equals(method)) {
                            return createOrderValidate(body, distributor);
                        } else if ("CreateOrder".equals(method)) {
                            return createOrder(body, distributor);
                        } else if ("CancelOrder".equals(method)) {
                            return cannelOrder( body, distributor, request);
                            // 取消订单指定门票(部分退票)
                        } else if ("PartialCancelOrder".equals(method)) {
                            return partialCancelOrder( body, distributor, request);
                        } else if ("QueryOrder".equals(method)) {
                            return queryOrder( body, distributor);
                        } else if ("QueryBalance".equals(method)) {
                            return queryBalance(body, distributor);
                        }

                    } catch (UnsupportedEncodingException e) {
                        log.info("同程-创建订单：请求参数-解析失败.");
                        resultMap.put(OTA_STATUS, XML_PARSE_FAIL);
                        resultMap.put(MSG, "XML解析失败");
                        return resultMap.toString();
                    } catch (Exception ex) {
                        log.debug("执行异常");
                        throw ex;
                    } finally {
                        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                } else {
                    log.debug("未获取到锁");
                    throw exception(OTA_REQUEST_TIMEOUT);
                }
            } catch (Exception ex) {
                throw exception(OTA_REQUEST_FAIL);
            }

        } catch (Exception e) {
            log.info("同程-创建订单：DES加密解密错误.");
            resultMap.put(OTA_STATUS, XML_PARSE_FAIL);
            resultMap.put(MSG, e.getMessage());
            return resultMap.toString();
        }
        return "";
    }

    /**
     * @param body
     * @param distributor
     * @return java.lang.String
     * @description 同程下单验证接口
     * @author 杨涛
     * @date 2025/2/22 17:15
     */
    String createOrderValidate(JSONObject body, DistributorRespDTO distributor) {
        JSONObject responseBody = new JSONObject();
        responseBody.put("validateResult", "2");
        responseBody.put("validateMessage", "校验售票规则未通过");
        try {
            TradeOrderCreateReqDTO order = this.parseOrder(body, distributor);
            //验证销售规则
            ProductSpuRespDTO productSpuRespDTO = productApi.getProduct(Long.parseLong(order.getItemlList().get(0).getProductId())).getCheckedData();

            TradeOrderRuleValidate.checkSaleRule(order.getItemlList().get(0), productSpuRespDTO);

            responseBody.put("validateResult", "1");
            responseBody.put("validateMessage", "验证通过");
            return TongChengResponse.create("1000", "验证通过", responseBody, distributor.getSecret());
        } catch (ServerException e) {
            log.error("分销", "同程下单", "createOrder", body.getStr("orderSerialId"), e.getMessage());
            return TongChengResponse.create(e.getCode().toString(), e.getMessage(), responseBody, distributor.getSecret());

        } catch (Exception e) {
            log.error("分销", "同程下单", "createOrder", body.getStr("orderSerialId"), e.getMessage());
            return TongChengResponse.create("5005", "校验售票规则未通过:" + e.getMessage(), responseBody, distributor.getSecret());
        }
    }

    /**
     * 创建订单（包含非实名制）
     */
    String createOrder(JSONObject body, DistributorRespDTO distributor) {
        RLock lock = null;
        try {
            //二、封装下单
            TradeOrderCreateReqDTO order = this.parseOrder(body, distributor);

            String key = order.getExternalOrderNo() + distributor.getId();
            lock = redissonClient.getLock(key);
            if (lock.tryLock(10, TimeUnit.SECONDS)) {

                //三、订单创建
                return this.savePayOrder(order.getExternalOrderNo(), order, true, distributor);

            } else {
                log.info("同程：重复提交");
                return TongChengResponse.create("5005", "重复提交", distributor.getSecret());
            }

        } catch (ServerException e) {
            log.error("分销", "同程下单", "createOrder", body.getStr("orderSerialId"), e.getMessage());
            return TongChengResponse.create(e.getCode().toString(), e.getMessage(), distributor.getSecret());
        } catch (Exception e) {
            log.error("分销", "同程下单", "createOrder", body.getStr("orderSerialId"), e.getMessage());
            return TongChengResponse.create("5005", "下单失败", distributor.getSecret());
        } finally {
            if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 封装下单
     */
    private TradeOrderCreateReqDTO parseOrder(JSONObject body, DistributorRespDTO distributor) throws Exception {
        Long distributorId = distributor.getId();
        List<TradeOrderCreateReqDTO.OrderItem> itemlList = new ArrayList<>();
        List<TradeOrderCreateReqDTO.OrderDetail> detailList = new ArrayList<>();
        TradeOrderCreateReqDTO order = new TradeOrderCreateReqDTO();

        order.setExternalOrderNo(body.getStr("orderSerialId"));
        Long productNo = body.getLong("productNo");

        TradeOrderCreateReqDTO.OrderProperty orderProperty = OtaConvert.INSTANCE.convert(distributorId.toString(), distributor.getName());
        order.setOrderProperty(orderProperty);
        Date useDate = body.getDate("travelDate");
        order.setTravelDate(useDate);
        //2、查询产品
        DistributorProductRespDTO distributorProduct = otaDistributorApi.getDistributorProductById(productNo).getCheckedData();
        ProductSpuRespDTO productSpuRespDTO = productApi.getProduct(distributorProduct.getProductId()).getCheckedData();
        order.setRoutePlanId(distributorProduct.getRoutePlanId());

        if (null == distributorProduct || distributorProduct.getIsUse() != 1) {
            throw new ServerException(2004, "产品不存在！");
        }

        Integer ticketsCount = body.getInt("tickets");
        //联系人
        TradeOrderCreateReqDTO.OrderUser orderUser = new TradeOrderCreateReqDTO.OrderUser();
        orderUser.setCredentialType(0);
        orderUser.setMobile(body.getStr("bookMobile"));
        orderUser.setContactName(body.getStr("bookName"));
        orderUser.setCredentialNo(body.getStr("idCard"));
        order.setOrderUser(orderUser);

        // 单位:元
        BigDecimal ticketPrice = distributorProduct.getSalePrice();

//        if (null != useDate) {
//            StockDayPriceQueryReqDTO queryReqDTO = new StockDayPriceQueryReqDTO();
//            queryReqDTO.setBusinessId(productNo);
//            queryReqDTO.setType(StockTypeEnum.DISTRIBUTOR_PRODUCT.getValue());
//            queryReqDTO.setDate(DateUtil.format(useDate, DatePattern.NORM_DATE_FORMATTER));
//            //查询日历价格
//            CommonResult<StockDayPriceRespDTO>  stockDayPrice = stockApi.getStockDayPrice(queryReqDTO);
//            if(stockDayPrice.getCode() == 0){
//                ticketPrice =stockDayPrice.getData().getPrice();
//            }
//        }

        if (ticketPrice != null) {
            BigDecimal orderAmt = ticketPrice.multiply(new BigDecimal(ticketsCount));
            order.setAmount(orderAmt);
            order.setPayAmount(orderAmt);
        }
        TradeOrderCreateReqDTO.OrderItem orderItem = new TradeOrderCreateReqDTO.OrderItem();
        orderItem.setProductId(distributorProduct.getProductId().toString());
        orderItem.setProductType(PRODUCT_BASE_TYPE_SELF);
        orderItem.setUseDate(useDate);
        List<DistributorProductRespDTO.DistributorProjectDTO> distributorProjectDTOS = otaDistributorApi.getProductByDistributor(distributor.getId(),distributorProduct.getProductId(),distributorProduct.getId()).getCheckedData();
        TradeOrderCreateReqDTO.OrderDetail orderDetail = OtaConvert.INSTANCE.convert(distributorProduct, ticketsCount,distributorProjectDTOS,ticketPrice);

        List<TradeOrderCreateReqDTO.Visitor> visitors = new ArrayList<>();
        JSONArray vistors = JSONUtil.parseArray(body.getStr("visitPerson"));
        // 售票规则验证购票方式(1:实名购票，3：无需实名)
        ProductSaleRuleRespDTO saleRule = productSpuRespDTO.getProductSaleRule();
        if (saleRule != null && saleRule.getIsLimitType() == 1 && CollUtil.isNotEmpty(vistors)) {
            for (int i = 0; i < vistors.size(); i++) {
                JSONObject item = vistors.getJSONObject(i);

                if (StringUtils.isEmpty(item.getStr("idCard"))) {
                    log.error("同程：创建订单：游客身份证为空不能下单.");
                    throw new ServerException(2001, "游客身份证为空不能下单！");
                }
                TradeOrderCreateReqDTO.Visitor visitor = new TradeOrderCreateReqDTO.Visitor();
                visitor.setCredentialNo(item.getStr("idCard"));
                visitor.setCredentialType(0);
                visitor.setName(item.getStr("name"));
                visitors.add(visitor);
            }
        } else {
            // 非实名制购票
            if (saleRule != null && saleRule.getIsLimitType() == 0) {
                visitors = OtaConvert.INSTANCE.convertOtaVisitorList(ticketsCount);
            }
        }
        if (saleRule != null && saleRule.getIsLimitType() == 1 && orderDetail.getCount() != visitors.size()) {
            // throw new RRException("本商品为实名制商品，出行人必填！");
            throw new ServerException(2001, "本商品为实名制商品，出行人必填！");
        }
//        //验证分销产品库存
//        StockDistributorDeductReqDTO deductReqDTO = new StockDistributorDeductReqDTO();
//        deductReqDTO.setDistributorProductId(productNo);
//        deductReqDTO.setNum(ticketsCount);
//        deductReqDTO.setUseDate(order.getTravelDate());
//        try {
//            stockApi.deductDistributorStock(deductReqDTO).getCheckedData();
//        } catch (Exception e) {
//            log.error("抖音日历票扣减库存异常：{}",  e.getMessage());
//            throw new ServerException(2001, "库存不足！");
//        }

        orderDetail.setVisitorList(visitors);
        detailList.add(orderDetail);
        orderItem.setDetailList(detailList);
        itemlList.add(orderItem);
        order.setItemlList(itemlList);
        return order;
    }

    /**
     * 带事务的创建订单
     *
     * @param otaOrderNo
     * @param order
     * @param isPay
     * @return
     */
    @Override
    public String savePayOrder(String otaOrderNo, TradeOrderCreateReqDTO order, boolean isPay, DistributorRespDTO distributor) {
        //重复验证
        TradeOrderDO tradeOrderInDB = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(otaOrderNo, order.getOrderProperty().getSourceId());
        if (tradeOrderInDB == null) {
            //创建订单
            CommonResult<TradeOrderRespDTO> result = tradeOrderService.createOrder(order);
            if (result.isError()) {
                return TongChengResponse.create("5001", result.getMsg(), new JSONObject(), distributor.getSecret());
            }
            TradeOrderRespDTO tradeOrderRespDTO = result.getCheckedData();
            //支付订单

            //验证分销商金额是否足够，在创建订单的时候计算订单总额，如果金额不够抛出异常 事务回滚。
            if (isPay) {
                PayOrderReqVO payOrderReqVO = new PayOrderReqVO();
                payOrderReqVO.setAccountId(distributor.getId().toString());
                //ota
                payOrderReqVO.setAccountType(PayAccountTypeEnum.OTA.getType());

                payOrderReqVO.setOrderId(tradeOrderRespDTO.getOrderId());
                payOrderReqVO.setPayAmount(order.getPayAmount());
                //预付款>授信
                Object[] payTypes = distributor.getPayType().split(",");
                if (CollectionUtils.containsAny("1", payTypes)) {
                    payOrderReqVO.setPayType(PayTypeEnum.ADVANCE_PAYMENT.getType());
                } else if (CollectionUtils.containsAny("2", payTypes)) {
                    payOrderReqVO.setPayType(PayTypeEnum.CREDIT_GRANTING.getType());
                }
                //统一支付、扣款、修改订单状态
                CommonResult<PayOrderRespVO> payResult = tradeOrderPayService.payOrder(payOrderReqVO);
                if (payResult.isError()) {
                    return TongChengResponse.create("5001", payResult.getMsg(), new JSONObject(), distributor.getSecret());
                }
            }
            //还回订单创建成功
            JSONObject responseBody = new JSONObject();
            responseBody.put("partnerOrderId", tradeOrderRespDTO.getOrderNo());

            //合作方入园辅助码
            responseBody.put("partnerCode", ""); // order.getOrderNo()
            //合作二维码链接地址
            responseBody.put("partnerQRCodeAddress", ""); // address
            //场次信息
            responseBody.put("partnerAreaInfo", "");

            // newRetCodeNotice(order);
            return TongChengResponse.create("1000", "创建订单成功", responseBody, distributor.getSecret());
            // 如果订单未支付
        } else if (tradeOrderInDB.getOrderStatus() == 0) {
            return TongChengResponse.create("5001", "订单状态为待付款(未扣余额)", new JSONObject(), distributor.getSecret());
            // 如果订单已过期
        } else if (tradeOrderInDB.getOrderStatus() == 6) {
            return TongChengResponse.create("5001", "订单状态为已过期", new JSONObject(), distributor.getSecret());
        } else {
            JSONObject responseBody = new JSONObject();
            responseBody.put("partnerOrderId", tradeOrderInDB.getOrderNo());
            responseBody.put("partnerCode", ""); // old.getOrderNo()
            //合作二维码链接地址
            responseBody.put("partnerQRCodeAddress", ""); // address
            //场次信息
            responseBody.put("partnerAreaInfo", "");

            this.newRetCodeNotice(tradeOrderInDB);
            return TongChengResponse.create("1000", "订单已存在", responseBody, distributor.getSecret());
        }
    }

    /**
     * 获取产品信息
     * 同程接口不支持日历价，只能通过同程商务配置日历价
     */
    String getProductInfo(JSONObject body, DistributorRespDTO distributor) {
        //查询产品

        Long productNo = body.getLong("productNo");
        DistributorProductRespDTO distributorProduct = otaDistributorApi.getDistributorProductById(productNo).getCheckedData();
        ProductSpuRespDTO productSpuRes = productApi.getProduct(distributorProduct.getProductId()).getCheckedData();
        //限制对象
        JSONArray productList = new JSONArray();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        if (null != productSpuRes) {
            //票种总价
            BigDecimal ticketPrice = distributorProduct.getSalePrice();

            JSONObject product = new JSONObject();
            product.put("id", productSpuRes.getId());
            product.put("productName", productSpuRes.getProductName());
            //零售价(单位:分)
            product.put("retailPrice", distributorProduct.getSalePrice().multiply(new BigDecimal(100)).intValue());
            //网络价(单位:分)
            product.put("webPrice", distributorProduct.getSalePrice().multiply(new BigDecimal(100)).intValue());
            //协议价(单位:分)
            product.put("contractPrice", ticketPrice);
//                product.put("sceneryNo", ticket.getScenicId());
//                product.put("sceneryName", ticket.getScenicName());
            //支付方式(0 未区分，1 景区到付,2 在线支付)
            product.put("payType", 2);
            //开始售卖日期(格式:yyyy-MM-dd)
            product.put("beginSaleDate", LocalDateTimeUtil.formatNormal(productSpuRes.getProductBasicRule().getSaleStartDate()));
            //结束售卖日期(格式:yyyy-MM-dd)
            product.put("endSaleDate", LocalDateTimeUtil.formatNormal(productSpuRes.getProductBasicRule().getSaleEndDate()));
            //有效期开始时间(格式:yyyy-MM-dd)
            product.put("beginValidDate", LocalDateTimeUtil.formatNormal(productSpuRes.getProductBasicRule().getCheckStartDate()));
            //有效期结束时间(格式:yyyy-MM-dd
            product.put("endValidDate", LocalDateTimeUtil.formatNormal(productSpuRes.getProductBasicRule().getCheckEndDate()));
            //屏蔽日期(yyyy-MM-dd,yyyy-MM-dd)
            product.put("shieldDate", "");
            // 售票规则验证购票方式(1:实名购票，3：无需实名)
            ProductSaleRuleRespDTO saleRule = productSpuRes.getProductSaleRule();
            if (saleRule != null && saleRule.getIsLimitType() == 1) {
                product.put("isRealName", 1); // 是否支持实名制(0 不支持 1 支持)
            } else if (saleRule != null && saleRule.getIsLimitType() == 0) {
                product.put("isRealName", 0); // 是否支持实名制(0 不支持 1 支持)
            }
            //验证方式 0 身份证 1 手机号 2手机发送识别码
            product.put("checkWay", 0);
            //取票方式
            product.put("getTicketWay", "现场取票");

            //是否支持退款 0 不支持 1 支持
            product.put("isCanRefund", productSpuRes.getProductRefundRule().getRefundRule() != 0 ? 1 : 0);
            //是否支持过期退款 0 不支持 1 支持
            product.put("isCanOverdueRefund", 0);
            //是否存在有效期（0 不存在 1 存在）
            product.put("isExistExpiryDate", 1);
            //有效期天数(isExistExpiryDate=1)和isExistExpiryDate配合使用只有存在有效期时这个值才有作用
            product.put("expiryDays", 0);
            //是否支持场次 0 不支持 1 支持
            product.put("isEvent", 0);
            //是否存在库存 0 不存在 1 存在
            product.put("isStock", 1);
            //预订限制信息
            JSONObject limitRule = new JSONObject();
            //下单提前天数（0 无限制， 1 提前1天，2提前2天）
            limitRule.put("advanceLimit", 1);
            //全天可预订最晚下单时间(HH:mm:ss)
            limitRule.put("lastOrderTimeLimit", "");
            product.put("limitRule", limitRule);
            productList.add(product);


        }

        //返回结果
        JSONObject responseBody = new JSONObject();
        responseBody.put("totalCount", 1);
        responseBody.put("productList", productList);
        return TongChengResponse.create("1000", "操作成功", responseBody, distributor.getSecret());
    }


    String cannelOrder(JSONObject body, DistributorRespDTO distributor, HttpServletRequest request) {
        RLock lock = null;
        try {
            String orderNo = body.getStr("partnerOrderId");
            //获取基础数据
            String otaOrderId = body.getStr("orderSerialId");
            //String reason = body.getStr("reason");
            int cancelCount = body.getInt("tickets");
            // isForceRefund == 1 强制退票
            Integer isForceRefund = body.getInt("isForceRefund");

            lock = redissonClient.getLock(orderNo + distributor.getId());
            if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
                JSONObject repBody = new JSONObject();

                TradeOrderDO order = tradeOrderRepositoryService.getOrderByNo(orderNo);
                TradeRefundCreateReqDTO refundCreateReqDTO = TradeRefundConvert.INSTANCE.convertOtaRefund(order.getId(), distributor.getId(), isForceRefund, orderNo);
                refundCreateReqDTO.setRefundAmount(order.getPayAmount());
                String resCode = "1000";
                String resMsg = "操作成功";

                RefundDO refund = tradeRefundRepositoryService.getRefundByOatNoAndOrder(orderNo, order.getId());
                if (refund == null) {
                    CommonResult<TradeRefundRespDTO> refundResult = tradeRefundService.refund(refundCreateReqDTO);
                    if (refundResult.isSuccess()) {
                        // 0.订单未找到 1.订单取消成功 2.订单取消审核中 3.订单取消失败
                        repBody.put("refundStatus", 1);
                    } else if (ObjectUtil.equals(refundResult.getCode(), REFUND_AUDITING.getCode())) {
                        repBody.put("refundStatus", 2);
                    }
                } else if (ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.AUDITING.getStatus()) || ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.PASS.getStatus())) {
                    repBody.put("refundStatus", 2);
                } else if ((ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.REFUND_FAIL.getStatus()) || ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.REFUSE.getStatus()))) {
                    repBody.put("refundStatus", 3);
                    // 4005:订单取消失败,不支持取消
                    resCode = "4005";
                    resMsg = RefundStatusEnum.getRefundNameByStatus(refund.getRefundStatus());

                } else {
                    repBody.put("refundStatus", 1);
                }

                // 返回OTA
                return TongChengResponse.create(resCode, resMsg, repBody, distributor.getSecret());
            } else {
                JSONObject repBody = new JSONObject();
                // 0.订单未找到 1.订单取消成功 2.订单取消审核中 3.订单取消失败
                repBody.put("refundStatus", 3);
                return TongChengResponse.create("4002", "重复提交", repBody, distributor.getSecret());
            }
        } catch (ServerException ex) {
            JSONObject rep_body = new JSONObject();
            rep_body.put("refundStatus", 3);
            rep_body.put("remark", ex.getMessage());
            return TongChengResponse.create("4002", ex.getMessage(), rep_body, distributor.getSecret());
        } catch (Exception ex) {
            JSONObject repBody = new JSONObject();
            repBody.put("refundStatus", 3);
            repBody.put("remark", "同程退单");
            return TongChengResponse.create("4002", "同程退单", repBody, distributor.getSecret());
        } finally {
            if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    String partialCancelOrder(JSONObject body, DistributorRespDTO distributor, HttpServletRequest request) {
        RLock lock = null;
        try {
            String orderNo = body.getStr("partnerOrderId");
            //获取基础数据
            String otaOrderId = body.getStr("orderSerialId");
            //String reason = body.getStr("reason");
            int cancelCount = body.getInt("tickets");
            // 申请取消的票号列表,数量须和取消票数一致
            JSONArray voucherList = body.getJSONArray("refundPartnerCodeList");
            voucherList = voucherList == null ? new JSONArray() : voucherList;
            List<String> ticketNoList = new ArrayList<>();
            String ticketNo = "";
            TradeOrderDO order = tradeOrderRepositoryService.getOrderByNo(orderNo);
            List<TradeRefundCreateReqDTO.RefundItem> refundItemList = new ArrayList<>();
            BigDecimal refundAmt = BigDecimal.ZERO;
            for (Object e : voucherList) {
                String code = (String) e;
                TradeDetailDO tradeDetail = tradeOrderRepositoryService.queryDetailVoucherCode(code, order.getId());
                TradeRefundCreateReqDTO.RefundItem refundItem = TradeRefundConvert.INSTANCE.convertRefundItem(tradeDetail.getActualPrice(), order.getId(), tradeDetail.getId(), tradeDetail.getVoucherCode());
                refundItemList.add(refundItem);
                refundAmt = refundAmt.add(tradeDetail.getActualPrice());
                refundItemList.add(refundItem);
            }
            // isForceRefund == 1 强制退票
            Integer isForceRefund = body.getInt("isForceRefund");
            TradeRefundCreateReqDTO refundCreateReqDTO = TradeRefundConvert.INSTANCE.convertOtaRefund(order.getId(), distributor.getId(), isForceRefund, orderNo);
            refundCreateReqDTO.setRefundAmount(refundAmt);
            refundCreateReqDTO.setItemlList(refundItemList);
            lock = redissonClient.getLock(orderNo + distributor.getId());
            if (lock.tryLock(10, TimeUnit.SECONDS)) {
                JSONObject repBody = new JSONObject();
                String resCode = "1000";
                String resMsg = "操作成功";

                RefundDO refund = tradeRefundRepositoryService.getRefundByOatNoAndOrder(orderNo, order.getId());
                if (refund == null) {
                    CommonResult<TradeRefundRespDTO> refundResult = tradeRefundService.refund(refundCreateReqDTO);
                    if (refundResult.isSuccess()) {
                        // 0.订单未找到 1.订单取消成功 2.订单取消审核中 3.订单取消失败
                        repBody.put("refundStatus", 1);
                    } else if (ObjectUtil.equals(refundResult.getCode(), REFUND_AUDITING.getCode())) {
                        repBody.put("refundStatus", 2);
                    }
                } else if (ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.AUDITING.getStatus()) || ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.PASS.getStatus())) {
                    repBody.put("refundStatus", 2);
                } else if ((ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.REFUND_FAIL.getStatus()) || ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.REFUSE.getStatus()))) {
                    repBody.put("refundStatus", 3);
                    // 4005:订单取消失败,不支持取消
                    resCode = "4005";
                    resMsg = RefundStatusEnum.getRefundNameByStatus(refund.getRefundStatus());

                } else {
                    repBody.put("refundStatus", 1);
                }
                // 返回OTA
                return TongChengResponse.create(resCode, resMsg, repBody, distributor.getSecret());
            } else {
                JSONObject repBody = new JSONObject();
                // 0.订单未找到 1.订单取消成功 2.订单取消审核中 3.订单取消失败
                repBody.put("refundStatus", 3);
                return TongChengResponse.create("4002", "重复提交", repBody, distributor.getSecret());
            }
        } catch (ServerException ex) {
            JSONObject repBody = new JSONObject();
            repBody.put("refundStatus", 3);
            repBody.put("remark", ex.getMessage());
            return TongChengResponse.create("4002", ex.getMessage(), repBody, distributor.getSecret());
        } catch (Exception ex) {
            JSONObject repBody = new JSONObject();
            repBody.put("refundStatus", 3);
            repBody.put("remark", "同程退订单指定门票");
            return TongChengResponse.create("4002", "同程退订单指定门票", repBody, distributor.getSecret());
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }
    }

    /**
     * 订单查询
     */
    String queryOrder(JSONObject body, DistributorRespDTO distributor) {
        String externalOrderNo = body.getStr("orderSerialId");
        String orderNo = body.getStr("partnerOrderId");
        try {
            TradeOrderDO order = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(externalOrderNo, distributor.getId().toString());
            JSONObject responseBody = new JSONObject();
            int orderStatus = 0;
            // 票数（当状态为0：返回票数为0； 1：返回订单票数； 2、3、4：返回退款票数；5：返回入园票数;
            if (order != null && orderNo.equals(order.getOrderNo())) {
                //0.订单未找到 1.订单创建成功 2.订单退款审核中 3.订单退款审核成功 4.订单退款审核失败 5.游客已入园
                if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.UNUSED.getStatus())) {
                    orderStatus = 1;
                } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.ALL_CHECK.getStatus()) || ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.PART_CHECK.getStatus())) {
                    orderStatus = 5;
                } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.ALL_REFUND.getStatus()) || ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.PARTIAL_REFUND.getStatus())) {
                    orderStatus = 3;
                }
                List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(order.getId());
                responseBody.put("tickets", detailDOList.size());
            } else {
                responseBody.put("tickets", 0);
            }

            RefundDO refund = tradeRefundRepositoryService.getRefundByOatNoAndOrder(orderNo, order.getId());
            if (refund != null) {
                if (ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.AUDITING.getStatus())) {
                    orderStatus = 2;
                } else if (ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.REFUSE.getStatus()) || ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.REFUND_FAIL.getStatus())) {
                    orderStatus = 4;
                }
            }

            responseBody.put("orderStatus", orderStatus);
            responseBody.put("remark", "");
            return TongChengResponse.create("1000", "订单查询成功", responseBody, distributor.getSecret());
        } catch (Exception e) {
            log.info("同程-查询订单失败：" + e.getMessage());
            log.error("分销", "同程查询订单", "queryOrder", orderNo, "同程：查询失败，异常：" + e.getMessage());
            return TongChengResponse.create("1002", "订单查询失败", new JSONObject(), distributor.getSecret());
        }
    }

    /**
     * 余额查询
     */
    String queryBalance(JSONObject body, DistributorRespDTO distributor) {
        JSONObject responseBody = new JSONObject();
        responseBody.put("balance", distributor.getBalance());
        return TongChengResponse.create("1000", "操作成功", responseBody, distributor.getSecret());
    }

    /**
     * 同程-消费send [我方->同程]
     */
    @Override
    public boolean consumeNotice(DistributorRespDTO distributor, Map<String, Object> map) {
        String orderNo = MapUtil.getStr(map, "orderNo");
        Long orderId = MapUtil.getLong(map, "orderId");
        String param = "";
        String sendUrl = "";
        Map<String, Object> ticketMap = tradeOrderRepositoryService.queryDetailCountByOrderId(orderId);
        int checkCount = MapUtil.getInt(ticketMap, "checkCount");
        int partCount = MapUtil.getInt(ticketMap, "partCount");
        int outTimeCount = MapUtil.getInt(ticketMap, "outTimeCount");
        int useCount = checkCount + partCount + outTimeCount;
        try {
//            // 订单核销通知接口
//            if(useCount == totalTicket){
//                JSONObject requestBody = new JSONObject();
//                requestBody.put("orderSerialId", MapUtil.getStr(map, "external_order_no"));
//                requestBody.put("partnerOrderId", orderNo);
//                requestBody.put("tickets", useCount); // 消费票数
//                requestBody.put("consumeDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
//                param = TongChengResponse.sign("ConsumeNotice", distributor.getAppid(), distributor.getSecret(), requestBody);
//                sendUrl = distributor.getServerUrl();
//                log.info("同程消费通知入参,partnerOrderId=" + orderNo + ";param=" + param);
//                String sendResult = SendHttps.sendPost(sendUrl, param, null);
//                Map<String, String> result = TongChengAuthUtil.decodeResponseJson(sendResult, distributor.getSecret());
//                String responseHead = result.get("responseHead");
//                log.info("同程消费通知返回,partnerOrderId=" + orderNo + ";responseHead=" + responseHead);
//                JSONObject res = JSON.parseObject(responseHead);
//                if ("1000".equals(res.getStr("res_code"))) {
//                    //记录消费通知
//                    notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 1);
//                    return true;
//                }
//                //记录消费通知
//                notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 0);
//                // 部分核销通知接口
//            } else {
            JSONObject requestBody = new JSONObject();
            requestBody.put("orderSerialId", MapUtil.getStr(map, "external_order_no")); // 三方订单流水号
            requestBody.put("partnerOrderId", orderNo); // 订单号
            requestBody.put("tickets", useCount); // 累计消费票数
            requestBody.put("consumeTickets", 1); // 本次消费票数
            requestBody.put("consumeDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); // 消费日期
            requestBody.put("consumeBatchNumber", MapUtil.getStr(map, "voucherCode")); // 核销批次号
            JSONArray consumeCodes = new JSONArray();
            JSONObject partnerCode = new JSONObject();
            partnerCode.put("partnerCode", MapUtil.getStr(map, "voucherCode")); // 入园码
            consumeCodes.add(partnerCode);
            requestBody.put("consumeCodes", consumeCodes); // 核销码集合
            param = TongChengResponse.sign("PartialConsume", distributor.getAppid(), distributor.getSecret(), requestBody);
            sendUrl = distributor.getServerUrl();
            log.info("同程部分核销通知入参,partnerOrderId=" + orderNo + ";param=" + param);
            String sendResult = HttpUtil.createPost(sendUrl).contentType("application/json")
                    .body(param)
                    .timeout(15000)
                    .execute().body();
            Map<String, String> result = TongChengAuthUtil.decodeResponseJson(sendResult, distributor.getSecret());
            String responseHead = result.get("responseHead");
            log.info("同程部分核销通知返回,partnerOrderId=" + orderNo + ";responseHead=" + responseHead);
            JSONObject res = JSONUtil.parseObj(responseHead);
            if ("1000".equals(res.getStr("res_code"))) {
                //记录消费通知
                notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 1);
                return true;
            }
            //记录消费通知
            notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 0);
            return false;
        } catch (Exception ex) {
            //记录消费通知
            notifyLogService.saveNotifyLog(map, sendUrl, param, ex.getMessage(), 0);
            log.error("同程消费通知失败,partnerOrderId=" + orderNo, ex.getMessage());
            return false;
        }
    }

    /**
     * 多码返码通知接口
     *
     * @param order
     * @return
     */
    public boolean newRetCodeNotice(TradeOrderDO order) {
        String param = "";
        String sendUrl = "";
        try {
            DistributorRespDTO distributor = this.getServer(order.getTenantId().toString());
            if (distributor == null) {
                return true;
            }
            // 非同程订单，返回true
            if (!(order.getSellMethod() == 1 && StringUtils.equals(distributor.getId().toString(), order.getSourceId()))) {
                return true;
            }
            JSONObject requestBody = new JSONObject();
            requestBody.put("orderSerialId", order.getExternalOrderNo()); // 三方订单流水号
            requestBody.put("partnerOrderId", order.getOrderNo()); // 订单号
            List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(order.getId());
            if (CollUtil.isNotEmpty(detailDOList)) {
                JSONArray multipleCodeList = new JSONArray();
                for (TradeDetailDO tradeDetail : detailDOList) {
                    JSONObject multipleCode = new JSONObject();
                    multipleCode.put("subPartnerSerialId", tradeDetail.getVoucherCode()); // 子订单号
                    multipleCode.put("partnerCode", tradeDetail.getVoucherCode()); // 入园辅助码
                    List<TradeVisitorDO> visitors = tradeOrderRepositoryService.queryVisitorByDetailId(tradeDetail.getId());
                    multipleCode.put("travelIDCard", visitors.get(0).getCredentialNo()); // travelIDCard 游客证件号
                    multipleCode.put("travelName", visitors.get(0).getName());        // travelName 游客姓名
                    // multipleCode.put("travelMobile", "");  // 联系方式
                    multipleCodeList.add(multipleCode);
                }
                requestBody.put("multipleCodeList", multipleCodeList); // 返码集合
            }
            param = TongChengResponse.sign("NewRetCodeNotice", distributor.getAppid(), distributor.getSecret(), requestBody);
            sendUrl = distributor.getServerUrl();
            // log.info("同程多码返码通知入参,partnerOrderId=" + order.getOrderNo() + ";param=" + param);
            String sendResult = HttpUtil.createPost(sendUrl).contentType("application/json")
                    .body(param)
                    .timeout(15000)
                    .execute().body();
            if (StringUtils.isBlank(sendResult)) {
                return false;
            }
            Map<String, String> result = TongChengAuthUtil.decodeResponseJson(sendResult, distributor.getSecret());
            String responseHead = result.get("responseHead");
            // log.info("同程多码返码返回,partnerOrderId=" + order.getOrderNo() + ";responseHead=" + responseHead);
            JSONObject res = JSONUtil.parseObj(responseHead);
            if ("1000".equals(res.getStr("res_code"))) {
                //记录消费通知
                // notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 1);
                return true;
            }
            //记录消费通知
            // notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 0);
            return false;
        } catch (Exception ex) {
            //记录消费通知
            // notifyLogService.saveNotifyLog(map, sendUrl, param, ex.getMessage(), 0);
            log.error("同程消费通知失败,partnerOrderId=" + order.getOrderNo(), ex.getMessage());
            return false;
        }
    }

    /**
     * @param distributor 分销商信息
     * @param map         参数
     * @return boolean
     * @description 退票结果异步通知同程
     * @author 杨涛
     * @date 2025/11/18 10:30
     */
    @Override
    public boolean refundNotice(DistributorRespDTO distributor, Map<String, Object> map) {
        String param = "";
        String sendUrl = "";
        String orderNo = MapUtil.getStr(map, "order_no");
        String refundNo = MapUtil.getStr(map, "refund_id");
        map.put("pid", orderNo);
        map.put("ticket_no", refundNo);
        try {
            JSONObject requestBody = new JSONObject();
            // 三方订单流水号
            requestBody.put("orderSerialId", MapUtil.getStr(map, "external_order_no"));
            // 订单号
            requestBody.put("partnerOrderId", orderNo);

            // 审核状态：0待审核，1审核通过，2审核驳回
            String auditStatus = MapUtil.getStr(map, "audit_status");
            boolean auditStatusFlag = StrUtil.equals(auditStatus, "1");
            boolean auditSatausRejectFlag = StrUtil.equals(auditStatus, "0");
            if (auditStatusFlag) {
                // 退款审核状态 0 失败 1 成功
                requestBody.put("refundStatus", 1);
                // 审核失败原因
                requestBody.put("remark", "");
            } else if (auditSatausRejectFlag) {
                // 退款审核状态 0 失败 1 成功
                requestBody.put("refundStatus", 0);
                // 审核失败原因
                requestBody.put("remark", MapUtil.getStr(map, "remark"));
            }

            // 订单退票数
            requestBody.put("tickets", MapUtil.getInt(map, "refund_tickets"));
            // 操作时间
            requestBody.put("datetime", DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            param = TongChengResponse.sign("RefundNotice", distributor.getAppid(), distributor.getSecret(), requestBody);

            sendUrl = distributor.getServerUrl();
            log.info("退票结果异步通知同程入参,partnerOrderId=" + orderNo + ";param=" + param);
            String sendResult = HttpUtil.createPost(sendUrl).contentType("application/json")
                    .body(param)
                    .timeout(15000)
                    .execute().body();
            Map<String, String> result = TongChengAuthUtil.decodeResponseJson(sendResult, distributor.getSecret());
            String responseHead = result.get("responseHead");
            log.info("退票结果异步通知同程返回,partnerOrderId=" + orderNo + ";responseHead=" + responseHead);
            JSONObject res = JSONUtil.parseObj(responseHead);
            // 处理结果返回码
            boolean resCodeFlag = "1000".equals(res.getStr("res_code"));
            if (resCodeFlag) {
                // 退票结果异步通知同程
                notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 1);
                return true;
            }
            // 退票结果异步通知同程
            notifyLogService.saveNotifyLog(map, sendUrl, param, responseHead, 0);
            return false;
        } catch (Exception ex) {
            // 退票结果异步通知同程
            notifyLogService.saveNotifyLog(map, sendUrl, param, ex.getMessage(), 0);
            log.error("退票结果异步通知同程失败,partnerOrderId=" + orderNo, ex.getMessage());
            return false;
        }
    }

    /**
     * String转换Integer
     */
    Integer strToInteger(String str, String msg) {
        Integer num = null;
        try {
            if (StringUtils.isBlank(str)) {
                return num;
            }
            return Integer.valueOf(str);
        } catch (Exception e) {
            log.error(msg + str);
        }
        return num;
    }

    /**
     * 获取分销商
     */
    DistributorRespDTO getServer(String tenantId) {

        DistributorRespDTO distributorRespDTO = otaDistributorApi.getDistributorByOtaAccount("", SYS_PRI_KEY_SAME_WAY_TYPECODE).getCheckedData();

        return distributorRespDTO;
    }
}



