package cn.freemud.service.impl;

import cn.freemud.adapter.OrderAdapter;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.base.log.LogTreadLocal;
import cn.freemud.constant.ResponseCodeConstant;
import cn.freemud.entities.dto.ConfirmOrderDto;
import cn.freemud.entities.dto.QueryOrdersResponseDto;
import cn.freemud.entities.vo.*;
import cn.freemud.entities.vo.encircle.CreateReserveOrderVo;
import cn.freemud.enums.*;
import cn.freemud.interceptor.ServiceException;
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.LogUtil;
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.sdk.api.assortment.order.enums.OrderSourceType;
import com.freemud.sdk.api.assortment.order.util.LockUtils;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;
import java.util.*;

/**
 * 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.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Slf4j
@Service
public class OrderAdapterServiceImpl implements OrderAdapterService {

    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 orderService;
    @Autowired
    private MCCafeOrderService mcCafeOrderService;

    private UniversalOrderService universalOrderService;
    @Autowired
    private CreateOrderServiceFactory createOrderServiceFactory;
    @Autowired
    private AssortmentCustomerInfoManager assortmentCustomerInfoManager;
    @Autowired
    private MallOrderService mallOrderService;
    @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;


    @Override
    public BaseResponse createOrderNew(CreateOrderVo createOrderVo) {
        AssortmentCustomerInfoVo assortmentCustomerInfoVo = assortmentCustomerInfoManager.getCustomerInfoByObject(createOrderVo.getSessionId());
        if (assortmentCustomerInfoVo == null || StringUtils.isEmpty(assortmentCustomerInfoVo.getMemberId())) {
            return ResponseUtil.error(ResponseResult.NOT_LOGIN);
        }
        // 用于测试 新创建订单接口  不是围餐, 并且 商户号 门店号都在配置里面
        LogUtil.info("是否进入新订单创建1 ",partnerIds,storeIds);
        LogUtil.info("是否进入新订单创建2 ",createOrderVo,assortmentCustomerInfoVo);
        if (!"wc".equals(createOrderVo.getChannelType()) &&
                !partnerIds.isEmpty() && partnerIds.contains(assortmentCustomerInfoVo.getPartnerId())
                && !storeIds.isEmpty() && storeIds.contains(assortmentCustomerInfoVo.getStoreId())) {
                LogUtil.info("进入新订单创建流程", createOrderVo,null);
            return this.createOrderUniversal(com.freemud.application.sdk.api.util.MapUtils.java2Map(createOrderVo));
        }
        // 扩展字段中存储 sessionKey
        createOrderVo.setSessionKey(assortmentCustomerInfoVo.getSessionKey());
        if (IappIdType.WC_XCX.getCode().equals(assortmentCustomerInfoVo.getIappId())) {  //i围餐
            BaseResponse baseResponse = null;
            CreateReserveOrderVo createReserveOrderVo = new CreateReserveOrderVo();
            createReserveOrderVo.setCarVer(createOrderVo.getCarVer());
            createReserveOrderVo.setRepastNumber(createOrderVo.getPeopleNumber());
            createReserveOrderVo.setSessionId(createOrderVo.getSessionId());
            createReserveOrderVo.setOrderUpdateVer(createOrderVo.getOrderUpdateVer());
            createReserveOrderVo.setCouponCode(createOrderVo.getCouponCode());
            createReserveOrderVo.setUseCustomerScore(createOrderVo.getUseCustomerScore());
            createReserveOrderVo.setCardCode(createOrderVo.getCardCode());
            if (createOrderVo.getOperation() == null) {
                throw new ServiceException(ResponseResult.ORDER_CREATE_OPERATION_ERROR);
            }
            switch (createOrderVo.getOperation()) {
                case 2:// 开台
                    baseResponse = encircleOrderService.createReserveOrder(createOrderVo);
                    break;
                case 3:// 下单
                    baseResponse = encircleOrderService.updateReserveOrder(createReserveOrderVo);
                    break;
                case 4:// 创建预支付订单
                    baseResponse = encircleOrderService.createPrepaymentOrder(createReserveOrderVo);
                    break;
                default:
                    throw new ServiceException(ResponseResult.ORDER_CREATE_OPERATION_ERROR);
            }
            return baseResponse;
        }

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

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

        //原标准点餐程序逻辑处理
        BaseResponse baseResponse = this.checkStandardParamInfo(createOrderVo);
        if (ObjectUtils.notEqual(baseResponse.getCode(), ResponseResult.SUCCESS.getCode())) {
            return baseResponse;
        }

        // 添加分布式锁，如果没有取得锁直接返回失败；整个方法执行完毕后会删掉该锁
        // 锁定秒数从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);
            }
            return orderService.createOrderNew(createOrderVo);
        } catch (Exception e) {
            throw e;
        } finally {
            //LockUtils.unlock(redisCache.getRedisTemplate(),createOrderKey);
        }
    }

    @Override
    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);
            }
            ApiLog.info("新订单业务对象 :",createOrderScene,createOrderBaseVo);
            return createOrderServiceFactory.getCreateOrderService(createOrderScene).createOrder(createOrderBaseVo, assortmentCustomerInfoVo, createOrderScene);
        } catch (Exception e) {
            throw e;
        } finally {
            //LockUtils.unlock(redisCache.getRedisTemplate(),createOrderKey);
        }
    }

    private BaseResponse validateParam(CreateOrderBaseVo createOrderBaseVo) {
        HibernateValidatorConfiguration configuration = Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(false);
        ValidatorFactory validatorFactory = configuration.buildValidatorFactory();
        Set<ConstraintViolation<CreateOrderBaseVo>> set = validatorFactory.getValidator().validate(createOrderBaseVo);
        if (CollectionUtils.isNotEmpty(set)) {
            Iterator<ConstraintViolation<CreateOrderBaseVo>> iterator = set.iterator();
            if (iterator.hasNext()) {
                ConstraintViolation<CreateOrderBaseVo> constraintViolation = iterator.next();
                return ResponseUtil.error(ResponseResult.PARAMETER_MISSING.getCode(), constraintViolation.getMessage());
            }
        }
        return ResponseUtil.success();
    }


    @Override
    public BaseResponse createMCCafeOrder(CreateOrderVo createOrderVo) {
        AssortmentCustomerInfoVo assortmentCustomerInfoVo = assortmentCustomerInfoManager.getCustomerInfoByObject(createOrderVo.getSessionId());
        if (assortmentCustomerInfoVo == null || StringUtils.isEmpty(assortmentCustomerInfoVo.getMemberId())) {
            return ResponseUtil.error(ResponseResult.NOT_LOGIN);
        }
        if (!mcCafePartnerId.equals(assortmentCustomerInfoVo.getPartnerId())) {
            return ResponseUtil.error(ResponseResult.LOGIN_STORE_ERROR);
        }
        // 扩展字段中存储 sessionKey
        createOrderVo.setSessionKey(assortmentCustomerInfoVo.getSessionKey());

        //原标准点餐程序逻辑处理
        BaseResponse baseResponse = this.checkStandardParamInfo(createOrderVo);
        if (ObjectUtils.notEqual(baseResponse.getCode(), ResponseResult.SUCCESS.getCode())) {
            return baseResponse;
        }

        // 添加分布式锁，如果没有取得锁直接返回失败；整个方法执行完毕后会删掉该锁
        // 锁定秒数从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);
            }
            return mcCafeOrderService.createMCCafeOrder(createOrderVo);
        } catch (Exception e) {
            throw e;
        } finally {
            //LockUtils.unlock(redisCache.getRedisTemplate(),createOrderKey);
        }
    }

    @Override
    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());
    }

    @Override
    public String paySuccessCallback(PaysuccessNoticeMessage message) {
        if (StringUtils.isEmpty(message.getTrans_id())) {
            return orderAdapter.newSendPayFaileMessage();
        }
        //添加分布式锁，如果没有取得锁直接返回失败；整个方法执行完毕后会删掉该锁
        String paySuccessKey = PAY_SUCCESS_KEY + message.getTrans_id();
        if (!LockUtils.lockAfter(redisCache.getRedisTemplate(), paySuccessKey)) {
            return orderAdapter.newSendPayFaileMessage();
        }
        try {
            ConfirmOrderDto confirmOrderDto = orderAdapter.convent2ConfirmOrderDto(message);
            // 蜜雪+混合支付专用：通过交易号从缓存中拿订单号，如果有数据则实际订单号为其value值
            String orderId = redisCache.getValue(RedisUtil.getPaymentTransIdOrderKey(message.getTrans_id()));
            if (StringUtils.isNotBlank(orderId)) {
                log.info("从缓存中获取的订单数据,trackingNo:{},transId:{},orderId:{}", LogTreadLocal.getTrackingNo(), confirmOrderDto.getOrderId(), orderId);
                confirmOrderDto.setOrderId(orderId);
            }
            Map<String, QueryOrdersResponseDto.DataBean.OrderBean> orderBeans = orderService.getOrderBeanByOrderId(confirmOrderDto.getOrderId());
            if (MapUtils.isEmpty(orderBeans)) {
                log.error("paySuccessCallback_queryOrderById_faild, trackingNo:{},PaysuccessNoticeMessage:{}", LogTreadLocal.getTrackingNo(), gson.toJson(message));
                return gson.toJson(message);
            }
            QueryOrdersResponseDto.DataBean.OrderBean orderBean = orderBeans.get(OrderBeanType.SAASORDER.getCode());//todo
            // 混合支付失败，取消订单
            if (!message.getResult_code().equals(ResponseCodeConstant.RESPONSE_SUCCESS)) {
                return orderService.cannelComPayOrder(confirmOrderDto, orderBean);
            }
            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())) {
                orderService.timeOutRefund(orderBean);
                return orderAdapter.sendPaySuccessNoticeMessage();
            }
            /**
             * 围餐处理
             */
            if (OrderSourceType.MEAL.getCode().equals(orderBean.getSource())) {
                return orderCommonService.paySuccessCallback(message, confirmOrderDto, orderBeans);
            }
            /**
             * 微商城处理
             */
            if (OrderSourceType.SAASMALL.getCode().equals(orderBean.getSource())) {
                return mallOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
            }
            /**
             * app订单处理
             */
            if (OrderSourceType.APP.getCode().equals(orderBean.getSource())) {
                if (orderBean.getBizType() == 6) {
                    return sellCouponOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
                }
                return appOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
            }
            //买券虚拟订单
            if (orderBean.getBizType() == 6) {
                return sellCouponOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
            }
            //麦咖啡订单处理
            if (mcCafePartnerId.equals(orderBean.getCompanyId())) {
                return mcCafeOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
            }
            /**
             * 默认点餐处理
             */
            return orderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
        } catch (Exception e) {
            throw e;
        } finally {
            //删除分布式锁
            redisCache.delete("saas:lockAfter:" + paySuccessKey);
        }
    }

    @Override
    public String mcCafePaySuccessCallback(PaysuccessNoticeMessage message) {
        //添加分布式锁，如果没有取得锁直接返回失败；整个方法执行完毕后会删掉该锁
        String paySuccessKey = PAY_SUCCESS_KEY + message.getTrans_id();
        if (!LockUtils.lockAfter(redisCache.getRedisTemplate(), paySuccessKey)) {
            return orderAdapter.newSendPayFaileMessage();
        }
        try {
            ConfirmOrderDto confirmOrderDto = orderAdapter.convent2ConfirmOrderDto(message);
            // 通过交易号从缓存中拿订单号，如果有数据则实际订单号为其value值
            String orderId = redisCache.getValue(RedisUtil.getPaymentTransIdOrderKey(confirmOrderDto.getOrderId()));
            if (StringUtils.isNotBlank(orderId)) {
                log.info("从缓存中获取的订单数据,trackingNo:{},transId:{},orderId:{}", LogTreadLocal.getTrackingNo(), confirmOrderDto.getOrderId(), orderId);
                confirmOrderDto.setOrderId(orderId);
            }
            Map<String, QueryOrdersResponseDto.DataBean.OrderBean> orderBeans = orderService.getOrderBeanByOrderId(confirmOrderDto.getOrderId());
            if (MapUtils.isEmpty(orderBeans)) {
                log.error("paySuccessCallback_queryOrderById_faild, trackingNo:{},PaysuccessNoticeMessage:{}", LogTreadLocal.getTrackingNo(), gson.toJson(message));
                return gson.toJson(message);
            }
            QueryOrdersResponseDto.DataBean.OrderBean orderBean = orderBeans.get(OrderBeanType.SAASORDER.getCode());
            if (!PayStatus.NOT_PAY.getCode().equals(orderBean.getPayStatus())) {
                return orderAdapter.sendPaySuccessNoticeMessage();
            }
            /**
             * 默认点餐处理
             */
            return mcCafeOrderService.paySuccessCallback(message, confirmOrderDto, orderBeans);
        } catch (Exception e) {
            throw e;
        } finally {
            //删除分布式锁
            redisCache.delete("saas:lockAfter:" + paySuccessKey);
        }
    }


    /**
     * 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.createOrder(createOrderVo, assortmentCustomerInfoVo);
        }
        return ResponseUtil.error(ResponseResult.PARAMETER_MISSING);
    }

    /**
     * 标准点餐参数校验
     *
     * @param createOrderVo
     * @return
     */
    private BaseResponse checkStandardParamInfo(CreateOrderVo createOrderVo) {
        if (StringUtils.isEmpty(createOrderVo.getSessionId())) {
            return ResponseUtil.error(ResponseResult.CREATE_ORDER_CHECK_SESSION_ERROR);
        }
        if (StringUtils.isEmpty(createOrderVo.getShopId())) {
            return ResponseUtil.error(ResponseResult.CREATE_ORDER_CHECK_STORE_ERROR);
        }
        if (createOrderVo.getOrderType() == null) {
            return ResponseUtil.error(ResponseResult.CREATE_ORDER_CHECK_ORDERTYPE_ERROR);
        }
        return ResponseUtil.success();
    }
}
