package cn.freemud.service.impl;

import cn.freemud.adapter.MessageNoticeAdapter;
import cn.freemud.adapter.OrderAdapter;
import cn.freemud.base.util.DateUtil;
import cn.freemud.constant.RedisKeyConstant;
import cn.freemud.constant.ResponseCodeConstant;
import cn.freemud.entities.dto.ConfirmOrderDto;
import cn.freemud.entities.dto.QueryOrdersResponseDto;
import cn.freemud.entities.dto.ShoppingCartBaseResponse;
import cn.freemud.entities.dto.shoppingCart.NewShoppingCartClearDto;
import cn.freemud.entities.vo.CreateOrderResponseVo;
import cn.freemud.entities.vo.PaysuccessNoticeMessage;
import cn.freemud.enums.OrderBeanType;
import cn.freemud.enums.PayStatus;
import cn.freemud.enums.RedisCacheEnum;
import cn.freemud.enums.ResponseResult;
import cn.freemud.interceptor.ServiceException;
import cn.freemud.redis.RedisCache;
import cn.freemud.service.CouponActivityService;
import cn.freemud.service.thirdparty.ShoppingCartClient;
import cn.freemud.utils.DateTimeUtil;
import cn.freemud.utils.LogUtil;
import cn.freemud.utils.RedisUtil;
import cn.freemud.utils.ValidationCode;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.freemud.api.assortment.datamanager.entity.db.AssortmentOpenPlatformWxapp;
import com.freemud.api.assortment.datamanager.entity.vo.AssortmentCustomerInfoVo;
import com.freemud.api.assortment.datamanager.manager.AssortmentOpenPlatformWxappManager;
import com.freemud.api.assortment.datamanager.meal.MealCacheManager;
import com.freemud.application.sdk.api.base.SDKCommonBaseContextWare;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.ordercenter.enums.OrderClientType;
import com.freemud.application.sdk.api.ordercenter.enums.ProductTypeEnum;
import com.freemud.application.sdk.api.ordercenter.request.OrderExtInfoDto;
import com.freemud.application.sdk.api.storecenter.request.ChangeTableOrderStateRequest;
import com.freemud.application.sdk.api.storecenter.service.StoreCenterService;
import com.freemud.application.sdk.api.structure.request.PushMessageNoticeDto;
import com.freemud.application.sdk.api.structure.service.MessageCenterClient;
import com.freemud.sdk.api.assortment.order.request.order.*;
import com.freemud.sdk.api.assortment.order.response.order.AssortmentAffirmGroupOrderResponse;
import com.freemud.sdk.api.assortment.order.response.order.BaseOrderResponse;
import com.freemud.sdk.api.assortment.order.response.order.QueryOrdersResponse;
import com.freemud.sdk.api.assortment.order.response.payment.OrderPayResponse;
import com.freemud.sdk.api.assortment.order.service.OrderCenterSdkService;
import com.freemud.sdk.api.assortment.payment.request.UnifiedOrderRequest;
import com.freemud.sdk.api.assortment.payment.response.UnifiedOrderResponse;
import com.freemud.sdk.api.assortment.payment.service.StandardPaymentService;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
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.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @version V1.6.0
 * @Title: OrderCommonService
 * @Description: 订单业务处理公共业务逻辑处理
 * @author: qin.zhou
 * @date: 2019/9/514:33
 * @Copyright: ${DATE.YARE} www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Service
public class OrderCommonService {
    @Autowired
    private AssortmentOpenPlatformWxappManager openPlatformWxappManager;
    @Value("${saas.reverseNotifyiDcUrl}")
    private String reverseNotifyiDcUrl;
    @Autowired
    private OrderAdapter orderAdapter;
    @Autowired
    private StandardPaymentService standardPaymentService;
    @Autowired
    private OrderCenterSdkService orderCenterSdkService;
    @Autowired
    private MealCacheManager mealCacheManager;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private StoreCenterService storeCenterService;
    @Autowired
    private ShoppingCartClient shoppingCartClient;
    @Autowired
    private MessageNoticeAdapter messageNoticeAdapter;
    @Autowired
    private MessageCenterClient messageNoticeClient;
    @Autowired
    private RedisService redisService;
    @Autowired
    private CouponActivityService couponActivityService;
    @Autowired
    private OrderServiceImpl orderService;

    private final Integer RESPONSE_SUCCESS_CODE = 100;
    /**
     * 创建预支付信息
     * cardCode svc卡号
     */
    public CreateOrderResponseVo createPrePaymentOrder(QueryOrdersResponse.DataBean.OrderBean orderBean,AssortmentCustomerInfoVo assortmentCustomerInfoVo, String partnerId, int cardAmount, String cardCode){
        OrderPayResponse orderPayResponse = null;
        String wxAppId = assortmentCustomerInfoVo.getWxAppId();
        //设置支付信息
        PaymentRequest paymentRequest = new PaymentRequest();
        paymentRequest.setOpenId(assortmentCustomerInfoVo.getOpenId());
        paymentRequest.setWxAppId(wxAppId);
        AssortmentOpenPlatformWxapp wxApp = openPlatformWxappManager.findByPartnerIdAndWxappId(partnerId, wxAppId);
        paymentRequest.setPrincipalName(wxApp.getPrincipalName());
        paymentRequest.setReverseNotifyiDcUrl(reverseNotifyiDcUrl);
        //修改订单信息
        OrderExtInfoDto orderExtInfoDto = JSONObject.parseObject(orderBean.getExtInfo(), OrderExtInfoDto.class) == null ? new OrderExtInfoDto() : JSONObject.parseObject(orderBean.getExtInfo(), OrderExtInfoDto.class);
        if(orderBean.getAmount() > 0 && StringUtils.isEmpty(cardCode)) {
            try {
                String transId = orderBean.getOid() + redisService.increment(RedisUtil.getPaymentTransIdSequenceKey(orderBean.getOid()), 1L, TimeUnit.DAYS);
                UnifiedOrderRequest request = orderAdapter.convent2UnifiedOrderRequest(orderBean, paymentRequest, orderBean.getAmount(), cardAmount, transId);

                if (SDKCommonBaseContextWare.getProfile().equals(SDKCommonBaseContextWare.profiles.DEFAULT.getProfile())
                        || SDKCommonBaseContextWare.getProfile().equals(SDKCommonBaseContextWare.profiles.DEV.getProfile())
                        || SDKCommonBaseContextWare.getProfile().equals(SDKCommonBaseContextWare.profiles.TEST.getProfile())) {
                    request.setAmount(1L);
                }
                ApiLog.info("支付transId :{},payRequest:{}", request.getTransId(), JSON.toJSONString(request));
                redisService.savePaymentTransIdOrder(RedisUtil.getPaymentTransIdOrderKey(transId), orderBean.getOid(), 1L, TimeUnit.DAYS);
                com.freemud.application.sdk.api.base.BaseResponse<UnifiedOrderResponse> responseBase = standardPaymentService.unifiedOrder(request, LogThreadLocal.getTrackingNo());
                if (!ResponseCodeConstant.RESPONSE_SUCCESS_STR.equals(responseBase.getCode())) {
                    return null;
                }
                orderPayResponse = orderAdapter.convent2OrderPayResponse(responseBase.getData());
                orderPayResponse.setWxAppid(paymentRequest.getWxAppId());
                orderPayResponse.setOpenId(paymentRequest.getOpenId());
                orderPayResponse.setPartnerId(orderBean.getCompanyId());
                orderPayResponse.setOrderId(orderBean.getOid());

                orderExtInfoDto.setPrePayTransId(request.getTransId());
            } catch (Exception e) {
                LogUtil.error("getPreOrderPay_error", JSONObject.toJSONString(orderBean), JSONObject.toJSONString(paymentRequest));
                //给出支付失败提示
                return null;
            }
        }else if(orderBean.getAmount() > 0 && StringUtils.isNotEmpty(cardCode)){
            //svc卡支付
            orderPayResponse = orderService.svcPay(cardCode, orderBean, paymentRequest, orderBean.getOid(), LogThreadLocal.getTrackingNo());
        }else if(orderBean.getAmount() < 0){
            throw new ServiceException(ResponseResult.PAY_AMOUNT_ERROR);
        }else{
            String fmId = "SPAY" + ValidationCode.getRandomUuid();
            orderPayResponse = orderAdapter.getOrderPayResponse(orderBean.getCompanyId(), paymentRequest,
                    orderBean.getOid(), fmId);
            orderExtInfoDto.setPrePayTransId(orderPayResponse.getPayTransId());
        }
        CreateOrderResponseVo createOrderResponseVo = orderAdapter.convent2CreateFatherSonOrderResponseVo(orderPayResponse,orderBean);
        orderExtInfoDto.setFmId(createOrderResponseVo.getFmId());
        orderExtInfoDto.setPrePayUserId(assortmentCustomerInfoVo.getMemberId());
        orderExtInfoDto.setPhone(assortmentCustomerInfoVo.getMobile());
        orderExtInfoDto.setAppid(wxAppId);
        OrderEditRequest orderEditRequest = new OrderEditRequest(orderBean.getOid(),
                JSONObject.toJSONString(orderExtInfoDto));
        orderEditRequest.setTrackingNo(LogThreadLocal.getTrackingNo());
        BaseOrderResponse baseOrderResponse = orderCenterSdkService.orderEdit(orderEditRequest);
        if (!ObjectUtils.equals(ResponseCodeConstant.RESPONSE_SUCCESS, baseOrderResponse.getErrcode())) {
            throw new ServiceException(ResponseResult.ORDER_EDIT_ERROR,baseOrderResponse.getErrmsg());
        }
        if (orderBean.getAmount() > 0) {
            createOrderResponseVo.setPaySuccess(false);
        } else {
            createOrderResponseVo.setPaySuccess(true);
        }
        return createOrderResponseVo;
    }

    /**
     * 支付后通知确认返回信息
     */
    public String sendPaySuccessNoticeMessage() {
        Map<String, Object> map = Maps.newTreeMap();
        map.put("code", 0);
        map.put("message", "success");
        return JSON.toJSONString(map);
    }

    /**
     * 支付后通知确认返回信息
     */
    public String newSendPaySuccessNoticeMessage() {
        Map<String, Object> map = Maps.newTreeMap();
        map.put("code", 100);
        map.put("message", "success");
        return JSON.toJSONString(map);
    }

    /**
     * 支付后通知失败返回信息
     */
    public String newSendPayFaileMessage() {
        Map<String, Object> map = Maps.newTreeMap();
        map.put("code", 500);
        map.put("message", "failed");
        return JSON.toJSONString(map);
    }

    /**
     * 修改桌号状态
     * @return
     */
    public com.freemud.application.sdk.api.base.BaseResponse changeTableNumberStatus(AssortmentCustomerInfoVo assortmentCustomerInfoVo, Integer tableNumberStatus){
        //调用门店服务锁定桌号
        ChangeTableOrderStateRequest tableOrderStateRequest = new ChangeTableOrderStateRequest();
        tableOrderStateRequest.setTableCode(assortmentCustomerInfoVo.getTableNumber());
        tableOrderStateRequest.setStoreCode(assortmentCustomerInfoVo.getStoreId());
        tableOrderStateRequest.setOrderState(tableNumberStatus);  //1开台  2清台
        tableOrderStateRequest.setPartnerId(assortmentCustomerInfoVo.getPartnerId());
        //tableOrderStateRequest.setUpdateUserId(assortmentCustomerInfoVo.getMemberId());
        tableOrderStateRequest.setUpdateUserId(assortmentCustomerInfoVo.getMemberId());
        tableOrderStateRequest.setRemark(tableNumberStatus == 1 ? "开台" : "清台");
        return storeCenterService.changeTableOrderState(tableOrderStateRequest,LogThreadLocal.getTrackingNo());
    }

    /**
     * 支付成功回调
     * @param message
     * @return
     */
    public String paySuccessCallback(PaysuccessNoticeMessage message, ConfirmOrderDto confirmOrderDto, Map<String, QueryOrdersResponseDto.DataBean.OrderBean> orderBeans) {
        QueryOrdersResponseDto.DataBean.OrderBean orderBean = orderBeans.get(OrderBeanType.SAASORDER.getCode());
        OrderExtInfoDto extInfo = JSONObject.parseObject(orderBean.getExtInfo(), OrderExtInfoDto.class);
        if(PayStatus.HAVE_PAID.getCode().equals(orderBean.getPayStatus()) && ObjectUtils.equals(1,orderBean.getPayType())){
            //发起退款  本期不考虑  极端情况
        }
        //调用清台sdk
        ClearTableRequest clearTableRequest = new ClearTableRequest();
        clearTableRequest.setPartnerId(orderBean.getCompanyId());
        clearTableRequest.setStoreId(orderBean.getShopId());
        clearTableRequest.setTableNumber(orderBean.getBarCounter());
        clearTableRequest.setUserId(extInfo == null ? "" : extInfo.getPrePayUserId());
        clearTableRequest.setOpClearTableEnum(ClearTableRequest.OpClearTableEnum.noOperationOrder);
        clearTableRequest.setOperator(orderBean.getUserName());
        orderCenterSdkService.clearTableNumber(clearTableRequest);
        //调用清除购物车接口
        NewShoppingCartClearDto shoppingCartClearDto = new NewShoppingCartClearDto();
        shoppingCartClearDto.setPartnerId(orderBean.getCompanyId());
        shoppingCartClearDto.setShopId(orderBean.getShopId());
        shoppingCartClearDto.setTableNumber(orderBean.getBarCounter());
        shoppingCartClearDto.setOperationType(3);
        ShoppingCartBaseResponse cartBaseResponse = shoppingCartClient.clearShoppingCart(shoppingCartClearDto);
        if(cartBaseResponse == null || ObjectUtils.notEqual(cartBaseResponse.getCode(),RESPONSE_SUCCESS_CODE)){
            ApiLog.info("支付成功回调通知清除购物车信息失败 request:{},response:{}",shoppingCartClearDto,cartBaseResponse);
        }
        //调用围餐订单完成接口
        AssortmentGroupOrderAffirmRequest affirmRequest = new AssortmentGroupOrderAffirmRequest();
        affirmRequest.setOrderClient(OrderClientType.WAI_MEAL.getIndex());
        affirmRequest.setOrderCode(orderBean.getOid());
        affirmRequest.setCompanyId(orderBean.getCompanyId());
        affirmRequest.setPayRequestNo(message.getOut_trade_no());
        affirmRequest.setActualPayAmount(message.getTotal_fee().longValue());
        affirmRequest.setPayTime(DateTimeUtil.getCurrentDateTimeStr());
        if (extInfo != null) {
            extInfo.setPayDate(DateUtil.convert2String(new Date(), "yyyy-MM-dd HH:mm:ss"));
            extInfo.setPayTransId(message.getOut_trade_no());
            affirmRequest.setUserId(extInfo.getPrePayUserId());
            affirmRequest.setUserName(orderBean.getUserName());
            affirmRequest.setMobile(extInfo.getPhone());
            affirmRequest.setExtInfo(JSON.toJSONString(extInfo));
        }
        affirmRequest.setOperator(orderBean.getUserName());
        AssortmentAffirmGroupOrderResponse groupOrderResponse = orderCenterSdkService.affirmGroupOrder(affirmRequest);
        if(ObjectUtils.notEqual(RESPONSE_SUCCESS_CODE,groupOrderResponse.getErrcode())){
            LogUtil.error("paySuccessCallback_payAccess_faild", JSON.toJSONString(message), JSON.toJSONString(groupOrderResponse));
            return this.newSendPayFaileMessage();
        }

        //若该订单使用了优惠券，则移除卡包,移除失败也不退款
        couponActivityService.callbackNotify(orderBean);

        // 删除订单自增缓存
        redisCache.delete(RedisUtil.getPaymentTransIdSequenceKey(orderBean.getOid()));
        // 删除支付交易号订单关系缓存
        redisCache.delete(RedisUtil.getPaymentTransIdOrderKey(message.getTrans_id()));

        this.sendPosMessage(orderBean.getCompanyId(),orderBean.getShopId(),orderBean.getOid());
        //支付回掉成功标记
        redisCache.save(RedisKeyConstant.KGD_PAYMENT_CALLBACK_FMID + message.getOut_trade_no(), message.getOut_trade_no(), 10L, TimeUnit.MINUTES);
        //返回调用结果
        return this.newSendPaySuccessNoticeMessage();
    }

    /**
     * 发送pos端消息
     */
    public void sendPosMessage(String partnerId, String storeId,String orderId) {
        PushMessageNoticeDto pushMessageNoticeDto = messageNoticeAdapter.convent2PushMessageNoticeDto(1, partnerId, storeId,
                null, orderId, null, null);
        messageNoticeClient.createMessage(pushMessageNoticeDto,LogThreadLocal.getTrackingNo());
    }

    /**
     * 尝试获取Redis锁 prefix
     * @return
     */
    public String redisLockInfo(AssortmentCustomerInfoVo assortmentCustomerInfoVo,RedisCacheEnum redisCacheEnum){
        StringBuilder sb = new StringBuilder(redisCacheEnum.getCode())
                .append(assortmentCustomerInfoVo.getPartnerId())
                .append(":")
                .append(assortmentCustomerInfoVo.getStoreId())
                .append(":")
                .append(assortmentCustomerInfoVo.getTableNumber());
        return sb.toString();
    }

    /**
     * 查询订单商品详情中是否有称重菜未称重
     * @return
     */
    public boolean queryExistWeightNoNum(QueryOrdersResponse.DataBean.OrderBean orderBean){
        for(QueryOrdersResponse.DataBean.OrderBean.ProductBean productBean : orderBean.getProductList()){
            if(ProductTypeEnum.WEIGHT_PRODUCT.getCode().equals(productBean.getProductType()) && (productBean.getWeight() == null || new BigDecimal("0.00").compareTo(productBean.getWeight()) >=  0)){
               return false;
            }
            if(ProductTypeEnum.SETMEAL_PRODUCT.getCode().equals(productBean.getProductType()) || ProductTypeEnum.SETMEAL_UPPRICE_PRODUCT.getCode().equals(productBean.getProductType())){
                if(CollectionUtils.isNotEmpty(productBean.getComboProduct())){
                    for(QueryOrdersResponse.DataBean.OrderBean.ProductBean productBeanSon : productBean.getComboProduct()){
                        if(ProductTypeEnum.WEIGHT_PRODUCT.getCode().equals(productBeanSon.getProductType()) && (productBeanSon.getWeight() == null || new BigDecimal("0.00").compareTo(productBeanSon.getWeight()) >= 0)){
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
}
