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


import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.collection.CollUtil;
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.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.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.ProductBasicRuleRespDTO;
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.controller.app.ota.vo.OtaVoucherVO;
import com.yc.ship.module.trade.convert.order.TradeOrderConvert;
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.TradeOrderStatusEnum;
import com.yc.ship.module.trade.enums.VoucherStatusEnum;
import com.yc.ship.module.trade.framework.common.ota.DesUtil;
import com.yc.ship.module.trade.framework.common.ota.ZshlAuthUtil;
import com.yc.ship.module.trade.framework.common.ota.ZshlResponse;
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.TradeOrderService;
import com.yc.ship.module.trade.service.order.bo.TradeVisitorBO;
import com.yc.ship.module.trade.service.ota.OtaService;
import com.yc.ship.module.trade.service.ota.ZshlService;
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.apache.logging.log4j.util.Base64Util;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

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.module.trade.enums.TravelhubDictTypeConstants.PRODUCT_BASE_TYPE_SELF;
import static com.yc.ship.module.trade.service.ota.OtaService.zshl;


/**
 * 通用接口
 *
 * @author qsl
 */
@Service(zshl)
@Slf4j
public class ZshlServiceImpl implements ZshlService, OtaService {

    @Resource
    private OtaDistributorApi otaDistributorApi;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ProductApi productApi;
    @Resource
    private TradeOrderService tradeOrderService;
    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;

    @Resource
    private TradeOrderPayService tradeOrderPayService;
    @Resource
    private NotifyLogService notifyLogService;

    @Resource
    private TradeRefundService tradeRefundService;

    @Resource
    private TradeRefundRepositoryService tradeRefundRepositoryService;

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

        // 获取抖音租户信息
        CommonResult<DistributorRespDTO> result = otaDistributorApi.getDistributorByOtaAccount(appId, "");
        if (result.isError()) {
            return null;
        }
        return result.getCheckedData();
    }

    /**
     * 签名校验
     */
    JSONObject checkSign(JSONObject jsonObj, String method, DistributorRespDTO distributor) throws UnsupportedEncodingException {
        // base64解密
        Map<String, String> requestMap = ZshlAuthUtil.decodeRequestJson(jsonObj, distributor.getSecret());
        // 请求头requestHead
        JSONObject requestHead = JSONUtil.parseObj(requestMap.get("requestHead"));
        //String method = requestHead.getStr("method");
        // 内容体requestBody
        JSONObject body = JSONUtil.parseObj(requestMap.get("requestBody"));
        log.debug("通用接口请求Head:{} Body:{}", requestHead.toString(), body.toString());
        if (ZshlAuthUtil.checkSign(ZshlAuthUtil.parseRequestHead(requestHead), method,
                distributor.getAppid(), distributor.getSecret(), requestMap.get("requestBodyNotDe")) && ZshlAuthUtil.checkAccount(requestHead, distributor.getAppid())) {
            log.debug("校验成功.");
            return body;
        } else {
            log.debug("校验失败.");
            throw new UnsupportedEncodingException("sign或帐号校验失败！");
        }

    }

    /**
     * 加密
     */
    @Override
    public String encrypt(String data) {
        JSONObject result = new JSONObject();
        try {
            JSONObject jsonObject = JSONUtil.parseObj(data);
            JSONObject requestHead = jsonObject.getJSONObject("requestHead");
            JSONObject requestBody = jsonObject.getJSONObject("requestBody");
            result.set("requestBody", DesUtil.encrypt(requestBody.toString(), requestHead.getStr("user_key")));
            requestHead.set("sign", ZshlAuthUtil.generateSign(requestHead, requestHead.getStr("user_id"), requestHead.getStr("user_key"), result.getStr("requestBody")));
            requestHead.remove("user_key");
            result.set("requestHead", requestHead);
        } catch (Exception ignored) {

        }
        return Base64Util.encode(result.toString());
    }

    /**
     * 解密
     */
    @Override
    public String decode(String data) {
        String result = "";
        try {
            JSONObject jsonObject = JSONUtil.parseObj(data);
            JSONObject requestHead = jsonObject.getJSONObject("requestHead");
            JSONObject request = JSONUtil.parseObj(Base64Decoder.decode(jsonObject.getStr("request")));
            String userKey = requestHead.getStr("userKey");
            Map<String, String> requestMap = ZshlAuthUtil.decodeRequestJson(request, userKey);
            result = JSONUtil.toJsonStr(requestMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 通用接口-消费send [我方->ota]
     */
    @Override
    public boolean consumeNotice(DistributorRespDTO distributor, Map<String, Object> map) {
        String orderNo = MapUtil.getStr(map, "orderNo");
        String param = "";
        String sendUrl = "";
        try {
            JSONObject requestBody = new JSONObject();
            requestBody.set("orderId", MapUtil.getStr(map, "external_order_no"));
            requestBody.set("partnerOrderId", orderNo);
            List<String> tickets = new ArrayList<>();
            tickets.add(MapUtil.getStr(map, "voucherCode"));
            requestBody.set("usedDetailIds", tickets);
            requestBody.set("consumeDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            param = ZshlResponse.sign("consumeNotice", distributor.getAppid(), distributor.getSecret(), requestBody);
//            String sendUrl = "http://jqapi.lvcang.cn/jingqu/OpenAPI/OpenService/Scenery";
            sendUrl = distributor.getServerUrl();
            log.info("通用接口消费通知入参,orderNo={};请求参数param={}", orderNo, param);
            //飞猪的网关只有contentType("text/plain")能进，如果其他分销商对接需要特别注意
            String sendResult = HttpUtil.createPost(sendUrl).contentType("text/plain")
                    .body(param)
                    .timeout(15000)
                    .execute().body();
            log.error("通用接口消费通知返回:{}", sendResult);
            if (StrUtil.isNotBlank(sendResult)) {
                Map<String, String> result = ZshlAuthUtil.decodeResponseJson(sendResult, distributor.getSecret());
                String responseHead = result.get("responseHead");
                log.debug("通用接口消费通知返回,orderNo={};responseHead={}", orderNo, 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);
            } else {
                notifyLogService.saveNotifyLog(map, sendUrl, param, "请求超时", 0);
            }
            return false;
        } catch (Exception ex) {
            //记录消费通知
            log.error("通用接口消费通知失败:", ex);
            notifyLogService.saveNotifyLog(map, sendUrl, param, ex.getMessage(), 0);

            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String doRequest(HttpServletRequest request, Long tenantId, String method, String jsonStr) {
        JSONObject body;
        DistributorRespDTO distributor = null;
        try {
            TenantContextHolder.setTenantId(tenantId);
            TenantContextHolder.setIgnore(false);
            // base64解密
            String json = Base64Decoder.decodeStr(jsonStr);
            // 转为object
            JSONObject jsonObj = JSONUtil.parseObj(json);
            JSONObject requestHead = jsonObj.getJSONObject("requestHead");
            //获取分销商信息
            distributor = getServer(requestHead.getStr("user_id"));
            if (distributor == null) {
                return ZshlResponse.create("5002", "帐号不存在", "");
            }
            //签名校验
            body = checkSign(jsonObj, method, distributor);
        } catch (UnsupportedEncodingException e) {
            log.info("通用接口：请求参数-解析失败.");
            return ZshlResponse.create("5002", e.getMessage(), distributor.getSecret());
        } catch (Exception e) {
            log.info("通用接口：DES加密解密错误.{}", e.getMessage());
            return ZshlResponse.create("5002", "解密错误", distributor.getSecret());
        }
        try {
            switch (method) {
                case "getProductInfo":
                    return getProductInfo(request, distributor, body);
                case "queryProductDetail":
                    return queryProductDetail(request, distributor, body);
                case "getProductList":
                    return getProductList(request, distributor, body);
                case "createOrder":
                    return createOrder(request, distributor, body);
                case "payOrder":
                    return orderPay(request, distributor, body);
                case "cancelOrder":
                case "cannelOrder":
                    return cancelOrder(request, distributor, body);
                case "cancelTicket":
                case "cannelTicket":
                    return cancelTicket(request, distributor, body);
                case "queryOrder":
                    return queryOrder(request, distributor, body);
                case "queryTicket":
                    return ZshlResponse.create("5005", "暂未实现", distributor.getSecret());
                default:
                    return ZshlResponse.create("5005", "调用方法不存在", distributor.getSecret());
            }
        } catch (Exception e) {
            return ZshlResponse.create("5005", e.getMessage(), distributor.getSecret());
        }
    }

    /**
     * 获取产品信息
     * 接口不支持日历价，只能通过ota商务配置日历价
     */
    public String getProductInfo(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        //查询产品
        Map<String, Object> param = new HashMap<>();

        param.put("scenicId", body.getStr("sceneryNo"));
        param.put("saleChannel", 1);
        int pageIndex = 0;
        int pageSize = 10;
        if (body.getInt("pageIndex") != null) {
            pageIndex = body.getInt("pageIndex") - 1;
        }
        if (body.getInt("pageSize") != null) {
            pageSize = body.getInt("pageSize");
        }
        List<DistributorProductRespDTO> productRespDTOList = otaDistributorApi.getProductListPageByDistributorId(distributor.getId(), pageIndex, pageSize).getCheckedData();
        //限制对象
        JSONArray productList = new JSONArray();
        if (CollUtil.isNotEmpty(productRespDTOList)) {
            for (DistributorProductRespDTO distributorProduct : productRespDTOList) {
                JSONObject product = new JSONObject();
                product.set("productId", distributorProduct.getProductId());
                product.set("productName", distributorProduct.getProductName());
                //单价(单位:元)
                product.set("price", distributorProduct.getSalePrice());
                ProductSpuRespDTO productSpuResp = productApi.getProduct(distributorProduct.getProductId()).getCheckedData();
                //开始售卖日期(格式:yyyy-MM-dd)
                ProductBasicRuleRespDTO productBasicRule = productSpuResp.getProductBasicRule();
                product.put("beginSaleDate", productBasicRule.getSaleStartDate());
                //结束售卖日期(格式:yyyy-MM-dd)

                product.put("endSaleDate", productBasicRule.getSaleEndDate());
                // 是否为期票 0否，1是
                product.put("isTerm", productBasicRule.getNeedPlayDate() == 1 ? 0 : 1);
                // 可检票开始时间
                product.put("checkStartDate", productBasicRule.getCheckStartDate());
                // 可检票结束时间
                product.put("checkEndDate", productBasicRule.getCheckEndDate());
                //是否支持退款 0 不支持 1 支持
                product.put("isCanRefund", productSpuResp.getProductRefundRule().getRefundRule() != 0 ? 1 : 0);
                product.put("imgUrl", productSpuResp.getCoverImgHorizontal());
                productList.add(product);
            }
        }
        //返回结果
        JSONObject responseBody = new JSONObject();
        int totalCount = productList.size();
        responseBody.put("totalCount", totalCount);
        responseBody.put("productList", productList);
        return ZshlResponse.create("1000", "操作成功", responseBody, distributor.getSecret());
    }

    /**
     * 获取产品详情接口
     */
    public String queryProductDetail(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        //产品id
        Long productId = body.getLong("productId");
        ProductSpuRespDTO productSpuResp = productApi.getProduct(productId).getCheckedData();
        if (productSpuResp == null) {
            return ZshlResponse.create("5002", "产品不存在", distributor.getSecret());
        }
        JSONObject responseBody = JSONUtil.parseObj(productSpuResp);
        return ZshlResponse.create("1000", "操作成功", responseBody, distributor.getSecret());
    }

    /**
     * 获取产品信息
     * 接口不支持日历价，只能通过ota商务配置日历价
     */
    public String getProductList(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        // 返回结果
        JSONObject responseBody = new JSONObject();
        return ZshlResponse.create("1000", "操作成功", responseBody, distributor.getSecret());
    }


    /**
     * 创建订单（包含非实名制）
     */
    public String createOrder(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        Long distributorId = distributor.getId();
        List<TradeOrderCreateReqDTO.OrderItem> itemlList = new ArrayList<>();
        List<TradeOrderCreateReqDTO.OrderDetail> detailList = new ArrayList<>();
        String key = "[ota-in]" + distributorId;
        RLock lock = redissonClient.getLock(key);
        TradeOrderCreateReqDTO order = new TradeOrderCreateReqDTO();
        try {
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                try {
                    String otaOrderId = body.getStr("orderId");
                    //查询产品信息
                    Long distributorProductId = body.getLong("productId");
                    int count = body.getInt("quantity");
                    Date travelDate = body.getDate("travelDate");
                    order.setTravelDate(travelDate);
                    order.setExternalOrderNo(otaOrderId);

                    DistributorProductRespDTO distributorProduct = otaDistributorApi.getDistributorProductById(distributorProductId).getCheckedData();
                    ProductSpuRespDTO productSpuRespDTO = productApi.getProduct(distributorProduct.getProductId()).getCheckedData();
                    order.setRoutePlanId(distributorProduct.getRoutePlanId());

                    TradeOrderCreateReqDTO.OrderProperty orderProperty = OtaConvert.INSTANCE.convert(distributorId.toString(), distributor.getName());
                    order.setOrderProperty(orderProperty);

                    BigDecimal ticketPrice = distributorProduct.getSalePrice();
                    if (ticketPrice != null) {

                        BigDecimal orderAmt = ticketPrice.multiply(new BigDecimal(count));
                        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(travelDate);
                    List<DistributorProductRespDTO.DistributorProjectDTO> distributorProjectDTOS = otaDistributorApi.getProductByDistributor(distributor.getId(), distributorProduct.getProductId(), distributorProduct.getId()).getCheckedData();
                    TradeOrderCreateReqDTO.OrderDetail orderDetail = OtaConvert.INSTANCE.convert(distributorProduct, count, distributorProjectDTOS, ticketPrice);
                    List<TradeOrderCreateReqDTO.Visitor> visitors = new ArrayList<>();

                    JSONArray visitPersons = JSONUtil.parseArray(body.getStr("visitPersons"));
                    // 售票规则验证购票方式(1:实名购票，3：无需实名)
                    ProductSaleRuleRespDTO saleRule = productSpuRespDTO.getProductSaleRule();
                    if (saleRule != null && saleRule.getIsLimitType() == 1 && CollUtil.isNotEmpty(visitPersons)) {
                        // 实名时
                        if (visitPersons.size() != count) {
                            return ZshlResponse.create("5005", "购票数量与传入的游客信息数量不一致", distributor.getSecret());
                        }
                        for (int i = 0; i < visitPersons.size(); i++) {
                            JSONObject item = visitPersons.getJSONObject(i);
                            TradeOrderCreateReqDTO.Visitor visitor = new TradeOrderCreateReqDTO.Visitor();
                            visitor.setCredentialNo(item.getStr("idCard"));
                            try {
                                if (item.get("idType") != null) {
                                    visitor.setCredentialType(item.getInt("idType"));
                                } else {
                                    visitor.setCredentialType(0);
                                }
                            } catch (Exception e) {
                                visitor.setCredentialType(0);
                            }
                            visitor.setName(item.getStr("name"));
                            visitor.setMobile(item.getStr("mobile"));
                            visitors.add(visitor);
                        }
                    } else {
                        // 非实名
                        String idCard = "";
                        // 有数据且数量一致时
                        if (CollUtil.isNotEmpty(visitPersons) && visitPersons.size() == count) {
                            for (int i = 0; i < visitPersons.size(); i++) {
                                JSONObject item = visitPersons.getJSONObject(i);
                                TradeOrderCreateReqDTO.Visitor visitor = new TradeOrderCreateReqDTO.Visitor();
                                visitor.setCredentialNo(item.getStr("idCard"));
                                visitor.setCredentialType(0);
                                visitor.setName(item.getStr("name"));
                                visitor.setMobile(item.getStr("mobile"));
                                visitors.add(visitor);
                            }
                        } else {
                            // 有数据且数量不一致时
                            if (CollUtil.isNotEmpty(visitPersons)) {
                                idCard = visitPersons.getJSONObject(0).getStr("idCard", "");
                            }
                            // 为空时
                            if (StringUtils.isBlank(idCard)) {
                                idCard = MapUtil.getStr(body, "idCard", "");
                            }
                            visitors = OtaConvert.INSTANCE.convertOtaVisitorList(count);
                        }
                    }
                    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);
                    orderDetail.setVisitorList(visitors);
                    detailList.add(orderDetail);
                    orderItem.setDetailList(detailList);
                    itemlList.add(orderItem);
                    order.setItemlList(itemlList);
                    try {
                        JSONObject responseBody = new JSONObject();
                        //重复下单验证
                        TradeOrderDO tradeOrderInDB = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(otaOrderId, order.getOrderProperty().getSourceId());
                        if (tradeOrderInDB != null) {
                            responseBody.put("orderId", tradeOrderInDB.getExternalOrderNo());
                            responseBody.put("partnerOrderId", tradeOrderInDB.getOrderNo());
                            responseBody.put("orderAmount", tradeOrderInDB.getPayAmount());
                            return ZshlResponse.create("5005", "订单已存在", responseBody, distributor.getSecret());
                        }
                        //开始下单
                        CommonResult<TradeOrderRespDTO> result = tradeOrderService.createOrder(order);
                        if (result.isSuccess()) {
                            TradeOrderRespDTO tradeOrderResp = result.getCheckedData();
                            //订单创建成功
                            responseBody.put("orderId", order.getExternalOrderNo());
                            responseBody.put("partnerOrderId", tradeOrderResp.getOrderNo());
                            responseBody.put("orderAmount", order.getPayAmount());
                            return ZshlResponse.create("1000", "创建订单成功", responseBody, distributor.getSecret());
                        } else {
                            return ZshlResponse.create("5005", result.getMsg(), distributor.getSecret());
                        }

                    } catch (ServerException ex) {
                        log.error("分销", "通用接口下单", "createOrder", body.getStr("orderId"), ex.getMessage());
                        return ZshlResponse.create("5005", ex.getMessage(), distributor.getSecret());
                    } catch (Exception e) {
                        log.info("通用接口-创建订单：失败.");
                        log.error("分销", "通用接口下单", "createOrder", body.getStr("orderId"), e.getMessage());
                        e.printStackTrace();
                        return ZshlResponse.create("5005", "下单失败", distributor.getSecret());
                    }

                } catch (Exception ex) {
                    log.debug("执行异常");
                    throw ex;
                } finally {
                    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                log.debug("未获取到锁");
                return ZshlResponse.create("5005", "请求超时", distributor.getSecret());
            }
        } catch (Exception ex) {
            return ZshlResponse.create("5005", "请求失败", distributor.getSecret());
        }
    }

    /**
     * 订单支付
     */
    public String orderPay(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        String orderNo = body.getStr("partnerOrderId");
        String otaOrderId = body.getStr("orderId");
        String key = "[ota-in]" + distributor.getId();
        RLock lock = redissonClient.getLock(key);
        try {
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                try {
                    TradeOrderDO order = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(otaOrderId, distributor.getId().toString());

                    if (order == null) {
                        return ZshlResponse.create("5001", "订单不存在", distributor.getSecret());
                    }
                    //支付成功
                    if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.UNUSED.getStatus())) {
                        // 订单已支付
                        JSONObject responseBody = new JSONObject();
                        responseBody.put("orderId", order.getExternalOrderNo());
                        responseBody.put("partnerOrderId", orderNo);
                        List<TradeVisitorBO> tradeVisitorBOList = tradeOrderRepositoryService.getVisitorVoucherListByOrderId(order.getId());
                        List<OtaVoucherVO> voucherList = TradeOrderConvert.INSTANCE.convertToVoucherList(tradeVisitorBOList);
                        responseBody.put("visitPersons", voucherList);
                        return ZshlResponse.create("1000", "支付成功", responseBody, distributor.getSecret());
                    }
                    PayOrderReqVO payOrderReqVO = new PayOrderReqVO();
                    payOrderReqVO.setAccountId(distributor.getId().toString());
                    //ota
                    payOrderReqVO.setAccountType(PayAccountTypeEnum.OTA.getType());
                    payOrderReqVO.setOrderId(order.getId());
                    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 ZshlResponse.create("5005", payResult.getMsg(), distributor.getSecret());
                    }

                    JSONObject responseBody = new JSONObject();
                    responseBody.put("orderId", order.getExternalOrderNo());
                    responseBody.put("partnerOrderId", orderNo);
                    List<TradeVisitorBO> tradeVisitorBOList = tradeOrderRepositoryService.getVisitorVoucherListByOrderId(order.getId());
                    List<OtaVoucherVO> voucherList = TradeOrderConvert.INSTANCE.convertToVoucherList(tradeVisitorBOList);
                    responseBody.put("visitPersons", voucherList);
                    return ZshlResponse.create("1000", "支付成功", responseBody, distributor.getSecret());
                } catch (ServerException ex) {
                    log.error("分销", "通用接口支付", "payOrder", orderNo, ex.getMessage());
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//因为异常被捕获,所以需要手动回滚事务
                    return ZshlResponse.create("5005", ex.getMessage(), distributor.getSecret());
                } catch (Exception e) {
                    log.info("通用接口-订单支付：失败.");
                    log.error("分销", "通用接口支付", "payOrder", orderNo, e.getMessage());
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//因为异常被捕获,所以需要手动回滚事务
                    return ZshlResponse.create("5005", "支付失败", distributor.getSecret());
                } finally {
                    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                log.debug("未获取到锁");
                return ZshlResponse.create("5005", "请求超时", distributor.getSecret());
            }
        } catch (Exception ex) {
            return ZshlResponse.create("5005", "请求失败", distributor.getSecret());
        }
    }

    /**
     * 退单
     */
    public String cancelOrder(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        String key = "[ota-in]" + distributor.getId();
        RLock lock = redissonClient.getLock(key);
        try {
            if (lock.tryLock(30, TimeUnit.SECONDS)) {
                try {
                    //获取参数
                    String otaOrderId = body.getStr("orderId", "");
                    String orderNo = body.getStr("partnerOrderId", "");
                    int cancelCount = body.getInt("refundQuantity");
                    //封装返回值
                    JSONObject responseBody = new JSONObject();
                    responseBody.set("orderId", otaOrderId);
                    responseBody.set("partnerOrderId", orderNo);
                    //查询订单信息

                    TradeOrderDO order = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(otaOrderId, distributor.getId().toString());

                    if (order == null) {
                        return ZshlResponse.create("5001", "订单不存在", distributor.getSecret());
                    }
                    List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(order.getId());
                    if (cancelCount < 1 || cancelCount > detailDOList.size()) {
                        return ZshlResponse.create("4002", "申请张数错误", distributor.getSecret());
                    }
                    //获取可退门票
                    int refundCount = 0;

                    if (CollUtil.isEmpty(detailDOList)) {
                        return ZshlResponse.create("4002", "门票不存在", distributor.getSecret());
                    }

                    TradeRefundCreateReqDTO refundCreateReqDTO = TradeRefundConvert.INSTANCE.convertOtaRefund(order.getId(), distributor.getId(), 0, orderNo);
                    refundCreateReqDTO.setRefundAmount(order.getPayAmount());
                    List<TradeDetailDO> refundList = new ArrayList<>();
                    for (TradeDetailDO detailDO : detailDOList) {
                        //验证门票是否可退：0初始状态，1待使用，2已取票，3已核销，4退款中,5已退票，6逾期核销,7已过期
                        if (detailDO.getVoucherStatus() > 0 && detailDO.getVoucherStatus() < 3) {
                            refundList.add(detailDO);
                        } else if (detailDO.getVoucherStatus() == 5) {
                            refundCount += 1;
                        }
                    }
                    if (CollUtil.isEmpty(refundList) && cancelCount == refundCount) {
                        return ZshlResponse.create("1000", "订单已退票成功", responseBody, distributor.getSecret());
                    } else if (refundList.size() != cancelCount) {
                        return ZshlResponse.create("4002", "申请张数与可退票张数数量不等", distributor.getSecret());
                    }
                    Long effectyCount = tradeOrderRepositoryService.queryEffectyCount(order.getId());
                    if (effectyCount == 0) {
                        return ZshlResponse.create("4002", "该订单无可退门票", distributor.getSecret());
                    }

                    try {
                        RefundDO refund = tradeRefundRepositoryService.getRefundByOatNoAndOrder(orderNo, order.getId());
                        if (refund == null) {
                            CommonResult<TradeRefundRespDTO> refundResult = tradeRefundService.refund(refundCreateReqDTO);
                            if (refundResult.isSuccess()) {
                                return ZshlResponse.create("1000", "退票成功", responseBody, distributor.getSecret());
                            }
                        }
                        return ZshlResponse.create("4002", "退票失败", distributor.getSecret());
                    } catch (ServerException ex) {
                        log.error("分销", "通用接口退票", "cannelOrder", body.getStr("partnerOrderId"), ex.getMessage());
                        return ZshlResponse.create("4002", ex.getMessage(), distributor.getSecret());
                    } catch (Exception e) {
                        log.error("分销", "通用接口退票", "cannelOrder", body.getStr("partnerOrderId"), e.getMessage());
                        e.printStackTrace();
                        return ZshlResponse.create("4002", "退票失败", distributor.getSecret());
                    }

                } catch (Exception ex) {
                    log.debug("执行异常");
                    throw ex;
                } finally {
                    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                log.debug("未获取到锁");
                return ZshlResponse.create("5005", "请求超时", distributor.getSecret());
            }
        } catch (Exception ex) {
            return ZshlResponse.create("5005", "请求失败", distributor.getSecret());
        }
    }

    /**
     * 退票
     */
    public String cancelTicket(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        String key = "[ota-in]" + distributor.getId();
        RLock lock = redissonClient.getLock(key);
        try {
            if (lock.tryLock(30, TimeUnit.SECONDS)) {
                try {
                    //获取参数
                    String otaOrderId = MapUtil.getStr(body, "orderId", "");
                    String orderNo = MapUtil.getStr(body, "partnerOrderId", "");
                    //退票门票号列表
                    List<String> refundDetailIds = (List<String>) body.get("refundDetailIds");
                    int cancelCount = 0;
                    if (refundDetailIds != null) {
                        cancelCount = refundDetailIds.size();
                    }
                    if (cancelCount == 0) {
                        return ZshlResponse.create("4002", "参数错误,请传入需要退票的门票号列表", distributor.getSecret());
                    }
                    //封装返回值
                    JSONObject responseBody = new JSONObject();
                    responseBody.put("orderId", otaOrderId);
                    responseBody.put("partnerOrderId", orderNo);
                    //查询订单信息
                    TradeOrderDO order = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(otaOrderId, distributor.getId().toString());

                    if (order == null) {
                        return ZshlResponse.create("5001", "订单不存在", distributor.getSecret());
                    }
                    List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(order.getId());
                    if (cancelCount > detailDOList.size()) {
                        return ZshlResponse.create("4002", "申请张数错误", distributor.getSecret());
                    }
                    //获取可退门票
                    int refundCount = 0;

                    if (CollUtil.isEmpty(detailDOList)) {
                        return ZshlResponse.create("4002", "门票不存在", distributor.getSecret());
                    }
                    TradeRefundCreateReqDTO refundCreateReqDTO = TradeRefundConvert.INSTANCE.convertOtaRefund(order.getId(), distributor.getId(), 0, orderNo);
                    //计算订单金额
                    List<TradeRefundCreateReqDTO.RefundItem> refundItemList = new ArrayList<>();
                    BigDecimal refundAmt = BigDecimal.ZERO;
                    for (TradeDetailDO detailDO : detailDOList) {
                        for (String voucherCode : refundDetailIds) {
                            if (ObjectUtil.equals(detailDO.getVoucherCode(), voucherCode)) {
                                //验证门票是否可退：0初始状态，1待使用，2已取票，3已核销，4退款中,5已退票，6逾期核销,7已过期
                                if (detailDO.getVoucherStatus() > 0 && detailDO.getVoucherStatus() < 3) {
                                    TradeRefundCreateReqDTO.RefundItem refundItem = TradeRefundConvert.INSTANCE.convertRefundItem(detailDO.getActualPrice(), order.getId(), detailDO.getId(), detailDO.getVoucherCode());
                                    refundItemList.add(refundItem);
                                    refundAmt = refundAmt.add(detailDO.getActualPrice());
                                } else if (detailDO.getVoucherStatus() == 5) {
                                    refundCount += 1;
                                }
                            }
                        }
                    }

                    if (CollUtil.isEmpty(refundItemList) && cancelCount == refundCount) {
                        return ZshlResponse.create("1000", "订单已退票成功", responseBody, distributor.getSecret());
                    } else if (refundItemList.size() != cancelCount) {
                        return ZshlResponse.create("4002", "申请张数与可退票张数数量不等", distributor.getSecret());
                    }
                    Long effectyCount = tradeOrderRepositoryService.queryEffectyCount(order.getId());
                    if (effectyCount == 0) {
                        return ZshlResponse.create("4002", "该订单无可退门票", distributor.getSecret());
                    }
                    refundCreateReqDTO.setRefundAmount(refundAmt);
                    refundCreateReqDTO.setItemlList(refundItemList);
                    try {
                        RefundDO refund = tradeRefundRepositoryService.getRefundByOatNoAndOrder(orderNo, order.getId());
                        if (refund == null) {
                            CommonResult<TradeRefundRespDTO> refundResult = tradeRefundService.refund(refundCreateReqDTO);
                            if (refundResult.isSuccess()) {
                                return ZshlResponse.create("1000", "退票成功", responseBody, distributor.getSecret());
                            }
                        }
                        return ZshlResponse.create("4002", "退票失败", distributor.getSecret());
                    } catch (ServerException ex) {
                        log.error("分销", "通用接口退票", "cannelOrder", body.getStr("partnerOrderId"), ex.getMessage());
                        return ZshlResponse.create("4002", ex.getMessage(), distributor.getSecret());
                    } catch (Exception e) {
                        log.error("分销", "通用接口退票", "cannelOrder", body.getStr("partnerOrderId"), e.getMessage());
                        e.printStackTrace();
                        return ZshlResponse.create("4002", "退票失败", distributor.getSecret());
                    }

                } catch (Exception ex) {
                    log.debug("执行异常");
                    throw ex;
                } finally {
                    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                log.debug("未获取到锁");
                return ZshlResponse.create("5005", "请求超时", distributor.getSecret());
            }
        } catch (Exception ex) {
            return ZshlResponse.create("5005", "请求失败", distributor.getSecret());
        }
    }

    public String queryOrder(HttpServletRequest request, DistributorRespDTO distributor, JSONObject body) {
        //获取参数
        String otaOrderId = MapUtil.getStr(body, "orderId", "");
        String orderNo = MapUtil.getStr(body, "partnerOrderId", "");
        //封装返回值
        JSONObject responseBody = new JSONObject();
        responseBody.set("orderId", otaOrderId);
        responseBody.set("partnerOrderId", orderNo);
        //查询订单信息
        TradeOrderDO order = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(otaOrderId, distributor.getId().toString());
        if (order == null) {
            return ZshlResponse.create("5001", "订单不存在", distributor.getSecret());
        }
        try {
            String status = "";
            // 订单状态:0代表订单失败,1表示订单成功(0待付款，1已付款，2已取票，3部分检票,4已检票，5已退票，6已过期)
            if (order.getOrderStatus() == 0 || order.getOrderStatus() == 6) {
                status = "0";
            } else {
                status = "1";
            }
            List<String> usedQuantity = new ArrayList<>();
            List<String> refundedQuantity = new ArrayList<>();
            //获取门票列表
            List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(order.getId());
            List<Map<String, Object>> resTicket = new ArrayList<>();
            if (CollUtil.isNotEmpty(detailDOList)) {
                for (TradeDetailDO detailDO : detailDOList) {
                    if (ObjectUtil.equals(detailDO.getVoucherStatus(), VoucherStatusEnum.VERIFIED.getStatus())
                            || ObjectUtil.equals(detailDO.getVoucherStatus(), VoucherStatusEnum.OVERDUE_VERIFIED.getStatus())) {
                        usedQuantity.add(detailDO.getVoucherCode());
                    } else if (ObjectUtil.equals(detailDO.getVoucherStatus(), VoucherStatusEnum.REFUND.getStatus())
                            || ObjectUtil.equals(detailDO.getVoucherStatus(), VoucherStatusEnum.PART_REFUND.getStatus())) {
                        refundedQuantity.add(detailDO.getVoucherCode());
                    }
                    Map<String, Object> map = new HashMap<>(16);
                    map.put("ticketNo", detailDO.getVoucherCode());
                    // 门票状态(-2重试中,-1下单失败,0初始状态,1待使用,2已取票,3已核销,4退款中,5,已退款,6逾期核销,7已过期)
                    map.put("ticketStatus", detailDO.getVoucherStatus());
                    List<TradeVisitorDO> visitorList = tradeOrderRepositoryService.queryVisitorByDetailId(detailDO.getId());
                    map.put("name", visitorList.get(0).getName());
                    map.put("idCard", visitorList.get(0).getCredentialNo());
                    resTicket.add(map);
                }
            }
            //返回数据
            responseBody.put("orderId", otaOrderId);
            responseBody.put("partnerOrderId", orderNo);
            responseBody.put("resTicket", resTicket); // 票号与游客证件号对应信息
            responseBody.put("orderStatus", String.valueOf(status));
            responseBody.put("orderQuantity", detailDOList.size());//订单总票数
            responseBody.put("usedQuantity", String.valueOf(usedQuantity.size()));//订单已经使用的总票数
            responseBody.put("refundedQuantity", String.valueOf(refundedQuantity.size()));//订单已经退款的总票数
            responseBody.put("usedDetailIds", usedQuantity);//订单已经消费的票Id列表
            responseBody.put("refundedDetailIds", refundedQuantity);//订单已经退票的票Id列表
            return ZshlResponse.create("1000", "订单查询成功", responseBody, distributor.getSecret());
        } catch (Exception e) {
            log.info("通用接口-查询订单失败：" + e.getMessage());
            log.error("分销", "通用接口查询订单", "queryOrder", orderNo, "通用接口：查询失败，异常：" + e.getMessage());
            return ZshlResponse.create("5005", "订单查询失败", new JSONObject(), distributor.getSecret());
        }
    }

    @Override
    public boolean refundNotice(DistributorRespDTO distributor, Map<String, Object> map) {
        return false;
    }


    public static void main(String[] args) {
        String body = "";
        try {
            body = DesUtil.decrypt("jBx2+bhFv8Daw+VebUcuy87eAmUA+XZ/wqkVnj/Y5Z88LAy+1IhaN7oCCNz08FrybMDF1115jldL9v8fUj+78XiPOX9ppFsOMQ01kwJDlgxmGbTs0OmUyO6zDodGXTIyJ2DcLkGlgwGb3EFPwNKZMqBBXlqbYOGpSJJ0Y5BuQ2ZQAkTqwRu85Kfv0AyJSFn/q1XCxT+cO5fLQmlfmTVXJUkyaP0F2OsG+895mevRW30SgQWgySeyu8QIiovUhlvkt1sMfeIDOYNo+8jIzVmQpP9TIXFly1H5WJPFU4gb8gn+02dd1OesKS4IFc0b22mPw9QxgrMC/28yWIKJNjfq/7SQFbN4C1heO4iP8I/4+SdKl1MC8/dBRocBeOlcHFJNz+CyBIndL+DpZ+67Ul9ZlK3WvLTz+g35y0JpX5k1VyVJMmj9BdjrBvvPeZnr0Vt9hJRef/DtFT7UDFWXiYzxi6HiLu8JVRBZ", "TFD9BEOK");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(body);
    }
}
