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.dto.ConfirmOrderDto;
import cn.freemud.entities.dto.order.CreateCashierOrderDto;
import cn.freemud.entities.vo.*;
import cn.freemud.enums.*;
import cn.freemud.interceptor.ServiceException;
import cn.freemud.management.service.handle.SaasOrderHandle;
import cn.freemud.management.thirdparty.OrderCallbackClient;
import cn.freemud.redis.RedisCache;
import cn.freemud.service.*;
import cn.freemud.service.universal.UniversalOrderService;
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.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.sdk.api.assortment.order.enums.OrderSourceType;
import com.freemud.sdk.api.assortment.order.util.LockUtils;
import com.google.gson.Gson;
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.stereotype.Service;

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


/**
 * 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;
    @Autowired
    private CashierOrderService cashierOrderService;

    //获取下单实现对象
    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 orderBeanSass = 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);
            }
            OrderBeanV1 orderBean = orderBeans.get(OrderBeanType.SAASORDER.getCode());
            // 注意，支付状态判断优先级最高
            if (!PayStatus.NOT_PAY.getCode().equals(orderBean.getPayStatus())) {
                return orderAdapter.sendPaySuccessNoticeMessage();
            }
            Integer client = OrderSourceType.getClientByCode(orderBean.getSource());
            //若是app订单超时回调了 订单已取消则做退款处理
            if (OrderStatus.CALCEL.getCode().equals(orderBean.getStatus()) && Arrays.asList(autoRefundClient.split(",")).contains(client.toString())
                    && Arrays.asList(autoRefundPartnerId.split(",")).contains(orderBean.getCompanyId())) {
                orderServiceImpl.timeOutRefund(orderBean);
                return orderAdapter.sendPaySuccessNoticeMessage();
            }
            //紧急开关时  判断订单bean是否存在
            orderBeanSass = orderBean;

            // 支付成功处理
            String result;
            switch (Objects.requireNonNull(OrderSourceType.valueOfCode(orderBean.getSource()))) {
                case MEAL:  //围餐订单处理
                    result = orderCommonService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                    break;
                case CASHIER: //收银单处理
                    result = cashierOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                    break;
                case SAASMALL: //微商城订单处理
                    result = mallOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                    break;
                case TIKTOKPAY: //抖音卖券订单处理
                    result = sellCouponOrderService.paySuccessCallbackForTiktok(message, confirmOrderDto, orderBeans);
                    break;
                case I_MEMBER: //会员订单
                    if (orderBean.getBizType() == 4) {
                        // 会员订单中 bizType为4的，为积分商城订单处理
                        result = pointsMallOrderService.paySuccessCallback(message,orderBeans);
                        break;
                    }
                    // bizType不等于4的，非积分商城订单，继续往下走
                case APP: //app订单
                    if (orderBean.getBizType() != 6) {
                        // bizType为卖券的订单，不走app订单逻辑
                        result = appOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                        break;
                    }
                default:
                    // 买券虚拟订单
                    if (orderBean.getBizType() == 6) {
                        result = sellCouponOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                    }
                    // 麦咖啡订单处理
                    if (mcCafePartnerId.equals(orderBean.getCompanyId())) {
                        result = mcCafeOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                    }
                    // 默认点餐处理
                    result = orderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
            }
            return result;
        } catch (Exception e) {
            throw e;
        } finally {
            //删除分布式锁
            redisCache.delete("saas:lockAfter:" + paySuccessKey);
            // 增加全局开关，当紧急方案打开时进行直接处理callBack消息
            if (orderBeanSass != null && orderCenterProperties.isUrgentCallbackOpen()) {
                // 查询
                OrderCallBackRequestVo requestVo = saasOrderHandle.convert2CallbackReq(orderBeanSass.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);
    }

}
