package cn.freemud.service.impl;

import cn.freemud.adapter.OrderAdapter;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.config.ApolloVariableConfig;
import cn.freemud.constant.RedisLockKey;
import cn.freemud.entities.bo.CreateOrderBONew;
import cn.freemud.entities.db.OpenPlatformOrderConfig;
import cn.freemud.entities.dto.ConfirmOrderDto;
import cn.freemud.entities.dto.order.CreateCashierOrderDto;
import cn.freemud.entities.dto.pay.SvcPayItem;
import cn.freemud.entities.dto.pay.svc.ConsumeHistoryCreateRequest;
import cn.freemud.entities.vo.*;
import cn.freemud.entities.vo.order.CashierCheckResponseVo;
import cn.freemud.entities.vo.order.GetOrderConfigRequestVo;
import cn.freemud.entities.vo.order.PaymentConfigVo;
import cn.freemud.entities.vo.order.PlugInParameter;
import cn.freemud.enums.*;
import cn.freemud.interceptor.ServiceException;
import cn.freemud.management.entities.dto.request.order.RefundSuccessCallbackVo;
import cn.freemud.management.service.handle.SaasOrderHandle;
import cn.freemud.management.thirdparty.OrderCallbackClient;
import cn.freemud.manager.OpenPlatformOrderConfigManager;
import cn.freemud.redis.RedisCache;
import cn.freemud.service.*;
import cn.freemud.service.thirdparty.SvcTransactionClient;
import cn.freemud.service.universal.factory.CreateOrderServiceFactory;
import cn.freemud.utils.RedisUtil;
import cn.freemud.utils.ResponseUtil;
import com.freemud.api.assortment.datamanager.entity.vo.AssortmentCustomerInfoVo;
import com.freemud.api.assortment.datamanager.enums.IappIdType;
import com.freemud.api.assortment.datamanager.manager.customer.AssortmentCustomerInfoManager;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.application.sdk.api.ordercenter.config.OrderCenterProperties;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.entities.vo.OrderCallBackRequestVo;
import com.freemud.application.sdk.api.ordercenter.enums.BizTypeEnum;
import com.freemud.application.sdk.api.ordercenter.enums.MarketTypeEnum;
import com.freemud.application.sdk.api.ordercenter.enums.NewOrderStatus;
import com.freemud.sdk.api.assortment.order.util.LockUtils;
import com.google.gson.Gson;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @version V1.6.0
 * @Title: OrderAdapterServiceImpl
 * @Description: 订单业务适配
 * @author: qin.zhou
 * @date: 2019/9/818:22
 * @Copyright: ${DATE.YARE} www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Service
public class OrderAdapterServiceImpl {

    private final String PAY_SUCCESS_KEY = "pay_success_key:";

    /**
     * 下单检查key，防止重复下单
     */
    private final String CREATE_ORDER_KEY = "create_order_key:";

    private static Gson gson = new Gson();

    @Value("${mccafe.partner.id}")
    private String mcCafePartnerId;

    /**
     * 商户号,用于测试 新创建订单 接口
     */
    @Value("${qa.createOrder.partnerId}")
    private List<String> partnerIds;

    /**
     * 门店号,用于测试 新创建订单 接口
     */
    @Value("${qa.createOrder.storeIds}")
    private List<String> storeIds;

    /**
     * 创单锁定的key
     */
    @Value("${create.order.key.expire:5}")
    private String createOrderKeyExpire;

    @Autowired
    private EncircleOrderService encircleOrderService;
    @Autowired
    private OrderServiceImpl orderServiceImpl;
    @Autowired
    private cn.freemud.service.Orderservice orderService;
    @Autowired
    private MCCafeOrderService mcCafeOrderService;

    //    private UniversalOrderService universalOrderService;
    @Autowired
    private CreateOrderServiceFactory createOrderServiceFactory;
    @Autowired
    private AssortmentCustomerInfoManager assortmentCustomerInfoManager;
    @Autowired
    private MallOrderService mallOrderService;
    @Autowired
    private PointsMallOrderService pointsMallOrderService;
    @Autowired
    private AppOrderService appOrderService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private OrderAdapter orderAdapter;
    @Autowired
    private OrderCommonService orderCommonService;
    @Autowired
    private SellCouponOrderServiceImpl sellCouponOrderService;
    @Value("${saas.autoRefund.client}")
    private String autoRefundClient;
    @Value("${saas.autoRefund.partnerId}")
    private String autoRefundPartnerId;
    @Autowired
    private OrderCenterProperties orderCenterProperties;
    @Autowired
    private SaasOrderHandle saasOrderHandle;
    @Autowired
    private OrderCallbackClient orderCallbackClient;
    @Autowired
    private SellCouponOrderServiceImpl sellCouponOrderServiceImpl;
    @Autowired
    private ApolloVariableConfig apolloVariable;
    @Lazy
    @Autowired
    private CashierOrderService cashierOrderService;
    @Autowired
    private PayServiceImpl payService;
    @Autowired
    private OpenPlatformOrderConfigManager openPlatformOrderConfigManager;
    @Autowired
    private SvcTransactionClient svcTransactionClient;

    //获取下单实现对象
    private OrderFactoryService getCreateOrderBean(AssortmentCustomerInfoVo assortmentCustomerInfoVo, CreateOrderVo createOrderVo) {
        // 扩展字段中存储 sessionKey
        createOrderVo.setSessionKey(assortmentCustomerInfoVo.getSessionKey());
        if (IappIdType.WC_XCX.getCode().equals(assortmentCustomerInfoVo.getIappId())) {  //i围餐
            return encircleOrderService;
        }
        //积分商城
        if (OrderChannelType.POINTSMALL.getCode().equals(createOrderVo.getChannelType())) {
            return pointsMallOrderService;
        }

        //微商城订单
        if (OrderChannelType.SAASMALL.getCode().equals(createOrderVo.getChannelType())) {
            return mallOrderService;
        }

        //APP下单
        if (UserLoginChannelEnum.APP.getCode().equals(assortmentCustomerInfoVo.getChannel())) {
            return appOrderService;
        }

        //抖音卖券
        if (Objects.equals(BizTypeEnum.SALE_COUPON.getBizType(), createOrderVo.getBizType())) {
            return sellCouponOrderServiceImpl;
        }
        return orderService;
    }

    /**
     * 创建无单 收银订单
     * 不需要查询购物车，没有商品，流程上 只需要创建一个订单然后唤起预支付就行了
     *
     * @param createOrderDto 请求信息
     */
    public CreateOrderResponseVo createCashierOrder(CreateCashierOrderDto createOrderDto) {
        AssortmentCustomerInfoVo member = assortmentCustomerInfoManager.getCustomerInfoByObject(createOrderDto.getSessionId());
        if (member == null || StringUtils.isEmpty(member.getMemberId())) {
            throw new ServiceException(ResponseResult.NOT_LOGIN);
        }
        //下单锁，防止重复点击
        String lockKey = MessageFormat.format(RedisLockKey.CREATE_ORDER, member.getMemberId());
        if (!LockUtils.lock(redisCache.getRedisTemplate(), lockKey, apolloVariable.getCreateOrderKeyExpire())) {
            throw new ServiceException(ResponseResult.ORDER_NOT_CREATE_ERROR);
        }
        //创建订单，返回预支付信息
        return cashierOrderService.createOrder(createOrderDto, member);
    }

    public BaseResponse createOrderNew(CreateOrderVo createOrderVo) {
        AssortmentCustomerInfoVo assortmentCustomerInfoVo = assortmentCustomerInfoManager.getCustomerInfoByObject(createOrderVo.getSessionId());
        if (assortmentCustomerInfoVo == null || StringUtils.isEmpty(assortmentCustomerInfoVo.getMemberId())) {
            return ResponseUtil.error(ResponseResult.NOT_LOGIN);
        }
        // 扩展字段中存储 sessionKey
        createOrderVo.setSessionKey(assortmentCustomerInfoVo.getSessionKey());
        // 用于测试 新创建订单接口  不是围餐, 并且 商户号 门店号都在配置里面
        if (!"wc".equals(createOrderVo.getChannelType()) &&
                !partnerIds.isEmpty() && partnerIds.contains(createOrderVo.getPartnerId())
                && !storeIds.isEmpty() && storeIds.contains(createOrderVo.getShopId())) {
            return this.createOrderUniversal(com.freemud.application.sdk.api.util.MapUtils.java2Map(createOrderVo));
        }
        // 添加分布式锁，如果没有取得锁直接返回失败；整个方法执行完毕后会删掉该锁
        // 锁定秒数从apollo获取，如果apollo没有设置，默认5秒
        String createOrderKey = CREATE_ORDER_KEY + assortmentCustomerInfoVo.getMemberId();
        try {
            Long expire = Long.valueOf(createOrderKeyExpire);
            if (!LockUtils.lock(redisCache.getRedisTemplate(), createOrderKey, expire)) {
                return ResponseUtil.error(ResponseResult.ORDER_NOT_CREATE_ERROR);
            }
            OrderFactoryService orderFactoryService = getCreateOrderBean(assortmentCustomerInfoVo, createOrderVo);
            CreateOrderBONew createOrderBO = new CreateOrderBONew(createOrderVo);
            //赋值缓存用户信息
            createOrderBO.setUserLoginInfoDto(assortmentCustomerInfoVo);
            return orderFactoryService.createOrder(createOrderBO);
        } catch (Exception e) {
            throw e;
        } finally {
            //LockUtils.unlock(redisCache.getRedisTemplate(),createOrderKey);
        }
    }

    public BaseResponse createOrderUniversal(Map<String, Object> param) {
        if (param.isEmpty()) {
            throw new ServiceException(ResponseResult.PARAMETER_MISSING);
        }
        // 商户逻辑判断  共同代码  begin
        String sessionId = (String) param.get("sessionId");
        if (StringUtils.isBlank(sessionId)) {
            throw new ServiceException(ResponseResult.SESSION_INVAILD);
        }
        AssortmentCustomerInfoVo assortmentCustomerInfoVo = assortmentCustomerInfoManager.getCustomerInfoByObject(sessionId);
        if (assortmentCustomerInfoVo == null || StringUtils.isEmpty(assortmentCustomerInfoVo.getMemberId())) {
            return ResponseUtil.error(ResponseResult.NOT_LOGIN);
        }
        // 商户逻辑判断  共同代码  end

        // 根据订单类型 获取需要操作的 实现类枚举
        CreateOrderSceneEnum createOrderScene = createOrderServiceFactory.getCreateOrderScene(param, assortmentCustomerInfoVo);
        // 根据订单类型, 转换成需要使用的对象                       1.这里可做转对象校验
        CreateOrderBaseVo createOrderBaseVo = createOrderServiceFactory.getCreateOrderVo(param, createOrderScene);

        // 添加分布式锁，如果没有取得锁直接返回失败；整个方法执行完毕后会删掉该锁
        // 锁定秒数从apollo获取，如果apollo没有设置，默认5秒
        String createOrderKey = CREATE_ORDER_KEY + assortmentCustomerInfoVo.getMemberId();
        try {
            Long expire = Long.valueOf(createOrderKeyExpire);
            if (!LockUtils.lock(redisCache.getRedisTemplate(), createOrderKey, expire)) {
                return ResponseUtil.error(ResponseResult.ORDER_NOT_CREATE_ERROR);
            }
//            AppLogUtil.infoLog("新订单业务对象 :",createOrderScene,createOrderBaseVo);
            return createOrderServiceFactory.getCreateOrderService(createOrderScene).createOrder(createOrderBaseVo, assortmentCustomerInfoVo, createOrderScene);
        } catch (Exception e) {
            throw e;
        } finally {
            //LockUtils.unlock(redisCache.getRedisTemplate(),createOrderKey);
        }
    }

    public BaseResponse createPrepay(CreatePrepayVo createPrepayVo) {
        AssortmentCustomerInfoVo assortmentCustomerInfoVo = assortmentCustomerInfoManager.getCustomerInfoByObject(createPrepayVo.getSessionId());
        if (assortmentCustomerInfoVo == null || StringUtils.isEmpty(assortmentCustomerInfoVo.getMemberId())) {
            return ResponseUtil.error(ResponseResult.NOT_LOGIN);
        }
        if (UserLoginChannelEnum.APP.getCode().equals(assortmentCustomerInfoVo.getChannel())) {
            return appOrderService.createPrepay(createPrepayVo);
        }
        throw new UnsupportedOperationException("暂不支持渠道：" + assortmentCustomerInfoVo.getChannel());
    }

    public String paySuccessCallback(PaysuccessNoticeMessage message) {
        if (StringUtils.isEmpty(message.getTrans_id())) {
            return orderAdapter.newSendPayFailedMessage();
        }
        //添加分布式锁，如果没有取得锁直接返回失败；整个方法执行完毕后会删掉该锁
        String paySuccessKey = PAY_SUCCESS_KEY + message.getTrans_id();
        if (!LockUtils.lockAfter(redisCache.getRedisTemplate(), paySuccessKey)) {
            return orderAdapter.paySuccessLockedMessage();
        }
        OrderBeanV1 orderBean = null;
        try {
            ConfirmOrderDto confirmOrderDto = orderAdapter.convent2ConfirmOrderDto(message);
            // 蜜雪+混合支付专用：通过交易号从缓存中拿订单号，如果有数据则实际订单号为其value值
            String orderId = redisCache.getValue(RedisUtil.getPaymentTransIdOrderKey(message.getTrans_id()));
            if (StringUtils.isNotBlank(orderId)) {
                confirmOrderDto.setOrderId(orderId);
            }
            Map<String, OrderBeanV1> orderBeans = orderServiceImpl.getOrderBeanByOrderId(confirmOrderDto.getOrderId());
            if (MapUtils.isEmpty(orderBeans)) {
                return gson.toJson(message);
            }
            orderBean = orderBeans.get(OrderBeanType.SAASORDER.getCode());
            // 注意，支付状态判断优先级最高
            if (!PayStatus.NOT_PAY.getCode().equals(orderBean.getPayStatus())) {
                return orderAdapter.sendPaySuccessNoticeMessage();
            }
            Integer client = Integer.parseInt(orderBean.getOrderClient());
            //若是app订单超时回调了 订单已取消则做退款处理
            if (NewOrderStatus.CLOSED.getIndex().equals(orderBean.getStatusV2()) && Arrays.asList(autoRefundClient.split(",")).contains(client.toString())
                    && Arrays.asList(autoRefundPartnerId.split(",")).contains(orderBean.getCompanyId())) {
                orderServiceImpl.timeOutRefund(orderBean);
                return orderAdapter.sendPaySuccessNoticeMessage();
            }
            // 支付成功处理
            String result = "";
            switch (client) {
                case 19:  //围餐订单处理 OrderClientType.WAI_MEAL.getIndex()
                    result = orderCommonService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                    break;
                case 27: //抖音卖券订单处理 OrderClientType.TIKTOKPAY.getIndex()
                    if (Objects.equals(BizTypeEnum.SALE_COUPON.getBizType(), orderBean.getBizType())) {
                        result = sellCouponOrderService.paySuccessCallbackForTiktok(message, confirmOrderDto, orderBeans);
                        break;
                    }
                    break;
                // bizType不等于4的，非积分商城订单，继续往下走
                case 12: //app订单 OrderClientType.APP.getIndex()
                    if (!Objects.equals(BizTypeEnum.SALE_COUPON.getBizType(), orderBean.getBizType())) {
                        // bizType为卖券的订单，不走app订单逻辑
                        result = appOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                        break;
                    }
                default://微信，支付宝渠道
                    // 积分商城订单
                    if (Objects.equals(BizTypeEnum.INTEGRAL_MALL.getBizType(), orderBean.getBizType())) {
                        result = pointsMallOrderService.paySuccessCallback(message, orderBeans);
                        break;
                    }
                    // 买券虚拟订单
                    if (Objects.equals(BizTypeEnum.SALE_COUPON.getBizType(), orderBean.getBizType())) {
                        result = sellCouponOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                        break;
                    }
                    // 微商城订单处理
                    if (Objects.equals(BizTypeEnum.MALL.getBizType(), orderBean.getBizType())) {
                        result = mallOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                        break;
                    }
                    // 收银单处理
                    if (Objects.equals(MarketTypeEnum.CASHIER.getIndex(), orderBean.getMarketingType().intValue())) {
                        result = cashierOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                        break;
                    }
                    // 麦咖啡订单处理
                    if (mcCafePartnerId.equals(orderBean.getCompanyId())) {
                        result = mcCafeOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                        break;
                    }
                    // 默认点餐处理(点餐业务和预定业务)
                    if (Objects.equals(BizTypeEnum.ORDINARY.getBizType(), orderBean.getBizType())
                            || Objects.equals(BizTypeEnum.ADVANCE_ORDER.getBizType(), orderBean.getBizType())) {
                        result = orderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                        break;
                    }
            }

            //储值卡订单消费后通知储值交易服务
            if (CollectionUtils.isNotEmpty(message.getSvcPayItems())) {
                sendSvcPayInfoToSvcTransaction(message.getSvcPayItems(), orderBean.getCompanyId(), orderBean.getOid(), orderBean.getUserId(), orderBean.getShopId());
            }
            return result;
        } catch (Exception e) {
            throw e;
        } finally {
            //删除分布式锁
            redisCache.delete("saas:lockAfter:" + paySuccessKey);
            // 增加全局开关，当紧急方案打开时进行直接处理callBack消息
            if (orderBean != null && orderCenterProperties.isUrgentCallbackOpen()) {
                // 查询
                OrderCallBackRequestVo requestVo = saasOrderHandle.convert2CallbackReq(orderBean.getOid(), 2, null, null);
                ApiLog.infoMessage("紧急方案 支付成功直接调用callback,orderCode:{},requestId:{}", requestVo.getOrderCode(), requestVo.getRequestId());
                orderCallbackClient.callbackOrder(requestVo);
            }
        }
    }

    /**
     * APP下单，下单带商品信息，不经过购物车服务，不唤起支付
     */
//    @Override
//    public BaseResponse appCreateOrder(AppCreateOrderVo createOrderVo) {
//        AssortmentCustomerInfoVo assortmentCustomerInfoVo = assortmentCustomerInfoManager.getCustomerInfoByObject(createOrderVo.getSessionId());
//        if (assortmentCustomerInfoVo == null || StringUtils.isEmpty(assortmentCustomerInfoVo.getMemberId())) {
//            return ResponseUtil.error(ResponseResult.NOT_LOGIN);
//        }
//        if (UserLoginChannelEnum.APP.getCode().equals(assortmentCustomerInfoVo.getChannel())) {
//            return appOrderService.createOrderOld(createOrderVo, assortmentCustomerInfoVo);
//        }
//        return ResponseUtil.error(ResponseResult.PARAMETER_MISSING);
//    }
    public BaseResponse<PlugInParameter> getPaymentConfig(PaymentConfigVo paymentConfigVo) {
        AssortmentCustomerInfoVo assortmentCustomerInfoVo = assortmentCustomerInfoManager.getCustomerInfoByObject(paymentConfigVo.getSessionId());
        if (assortmentCustomerInfoVo == null || StringUtils.isEmpty(assortmentCustomerInfoVo.getMemberId())) {
            return ResponseUtil.error(ResponseResult.NOT_LOGIN);
        }
        //周周惠插件要返回参数
        if (paymentConfigVo.getPlugInType() != null && paymentConfigVo.getPlugInType() == 2) {
            return ResponseUtil.success(payService.getPlugInParameter(paymentConfigVo.getPartnerId(), assortmentCustomerInfoVo.getWxAppId(), paymentConfigVo.getShopId()));
        }

        //1元插件要返回参数
        return ResponseUtil.success(payService.getPlugInParameter(paymentConfigVo.getPartnerId(), assortmentCustomerInfoVo.getWxAppId()));

    }

    /**
     * 无单收银使用储值卡混合支付
     */
    public CashierCheckResponseVo cashierCheck(CreateCashierOrderDto createOrderDto) {
        AssortmentCustomerInfoVo member = assortmentCustomerInfoManager.getCustomerInfoByObject(createOrderDto.getSessionId());
        if (member == null || StringUtils.isEmpty(member.getMemberId())) {
            throw new ServiceException(ResponseResult.NOT_LOGIN);
        }
        //校验储值卡余额
        return cashierOrderService.cashierCheck(createOrderDto, member);
    }

    /**
     * 获取餐盒费配置
     */
    public String getOrderConfig(GetOrderConfigRequestVo request) {
        OrderConfigEnum configType = OrderConfigEnum.getOrderConfigType(request.getType());
        if (null == configType)
            throw new ServiceException(ResponseResult.PARAMETER_MISSING);

        String key = configType.getKey() + request.getPartnerId() + "_" + request.getMiniAppId();
        String configStr = redisCache.hashGet(key, configType.getType());
        if (StringUtils.isBlank(configStr)) {
            OpenPlatformOrderConfig openPlatformOrderConfig = openPlatformOrderConfigManager.getOrderConfigByType(request);
            if (null != openPlatformOrderConfig) {
                configStr = openPlatformOrderConfig.getTypeValue();
            }
        }

        return configStr;
    }

    private void sendSvcPayInfoToSvcTransaction(List<SvcPayItem> svcPayItems, String partnerId, String orderCode, String memberId, String storeId) {
        ConsumeHistoryCreateRequest request = new ConsumeHistoryCreateRequest();
        try {
            request.setPartnerId(partnerId);
            request.setOrderCode(orderCode);
            request.setMemberId(memberId);
            request.setStoreId(storeId);
            List<String> svcTransIds = svcPayItems.stream().map(SvcPayItem::getSvcTransId).collect(Collectors.toList());
            request.setCardRequestNo(svcTransIds);

            svcTransactionClient.consumeHistoryCreate(request);
        } catch (Exception e) {
            ErrorLog.printErrorLog("sendSvcPayInfoToSvcTransaction", "paySuccessCallback", request, e);
        }

    }

}
