package org.apache.rocketmq.gateway.common.service.impl;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.request.QueryOrderRequest;
import org.apache.rocketmq.common.response.QueryOrderResponse;
import org.apache.rocketmq.gateway.common.dao.dataobject.SecKillProductDobj;
import org.apache.rocketmq.gateway.common.dto.CodeMsg;
import org.apache.rocketmq.gateway.common.dto.Result;
import org.apache.rocketmq.gateway.common.dto.request.ChargeOrderRequest;
import org.apache.rocketmq.gateway.common.dto.response.ChargeOrderResponse;
import org.apache.rocketmq.gateway.common.init.SecKillProductConfig;
import org.apache.rocketmq.gateway.common.manager.OrderQueryManager;
import org.apache.rocketmq.gateway.common.service.SecKillChargeService;
import org.apache.rocketmq.gateway.common.util.LogExceptionWapper;
import org.apache.rocketmq.gateway.mq.SecKillChargeOrderProducer;
import org.apache.rocketmq.message.constant.MessageProtocolConst;
import org.apache.rocketmq.message.protocol.ChargeOrderMsgProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.UUID;

/**
 * @author snowalker
 * @version 1.0
 * @date 2019/6/14 23:04
 * @className SecKillChargeServiceImpl
 * @desc 秒杀下单service实现
 */
@Service(value = "secKillChargeService")
public class SecKillChargeServiceImpl implements SecKillChargeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SecKillChargeServiceImpl.class);

    @Autowired
    SecKillProductConfig productConfig;

    @Autowired
    SecKillChargeOrderProducer secKillChargeOrderProducer;

    @Autowired
    OrderQueryManager orderQueryManager;

    /**
     * 秒杀下单前置参数校验
     * @param chargeOrderRequest
     * @param sessionId
     * @return
     */
    @Override
    public boolean checkParamsBeforeSecKillCharge(ChargeOrderRequest chargeOrderRequest, String sessionId) {
        // 入参校验
        if (chargeOrderRequest == null) {
            LOGGER.info("sessionId={},下单请求参数chargeOrderRequest为空,返回下单失败", sessionId);
            return false;
        }
        LOGGER.info("sessionId={},下单开始,下单请求参数chargeOrderRequest=[{}].", sessionId, JSON.toJSONString(chargeOrderRequest));
        String userPhoneNum = chargeOrderRequest.getUserPhoneNum();
        String chargePrice = chargeOrderRequest.getChargePrice();
        String prodId = chargeOrderRequest.getProdId();

        if (StringUtils.isBlank(prodId) || StringUtils.isBlank(chargePrice) || StringUtils.isBlank(userPhoneNum)) {
            LOGGER.info("sessionId={},下单必要参数为空,返回下单失败", sessionId);
            return false;
        }
        // 价格合法性校验 是否>0?
        BigDecimal chargePriceDecimal = new BigDecimal(chargePrice);
        if (chargePriceDecimal.longValue() < 0) {
            LOGGER.info("sessionId={},商品交易金额小于0,价格非法,返回下单失败", sessionId);
            return false;
        }
        return true;
    }

    /**
     * 秒杀下单前置商品校验
     * @param prodId
     * @param sessionId
     * @return
     */
    @Override
    public boolean checkProdConfigBeforeKillCharge(String prodId, String sessionId) {
        // 商品校验
        SecKillProductDobj productDobj = (SecKillProductDobj) productConfig.getRedisTemplate().opsForValue().get(prodId);
        if (productDobj == null) {
            LOGGER.info("sessionId={},prodId={},对应的商品信息不存在,返回下单失败", sessionId, prodId);
            return false;
        }
        return true;
    }

    /**
     * 秒杀订单入队
     * @param chargeOrderRequest
     * @param sessionId
     * @return
     */
    @Override
    public Result secKillOrderEnqueue(ChargeOrderRequest chargeOrderRequest, String sessionId) {

        // 订单号生成,组装秒杀订单消息协议
        String orderId = UUID.randomUUID().toString();
        String phoneNo = chargeOrderRequest.getUserPhoneNum();

        ChargeOrderMsgProtocol msgProtocol = new ChargeOrderMsgProtocol();
        msgProtocol.setUserPhoneNo(phoneNo)
                .setProdId(chargeOrderRequest.getProdId())
                .setChargeMoney(chargeOrderRequest.getChargePrice())
                .setOrderId(orderId);
        String msgBody = msgProtocol.encode();
        LOGGER.info("秒杀订单入队,消息协议={}", msgBody);

        DefaultMQProducer mqProducer = secKillChargeOrderProducer.getProducer();
        // 组装RocketMQ消息体
        Message message = new Message(MessageProtocolConst.SECKILL_CHARGE_ORDER_TOPIC.getTopic(), msgBody.getBytes());
        try {
            // 消息发送
            SendResult sendResult = mqProducer.send(message);
            // TODO 判断SendStatus
            if (sendResult == null) {
                LOGGER.error("sessionId={},秒杀订单消息投递失败,下单失败.msgBody={},sendResult=null", sessionId, msgBody);
                return Result.error(CodeMsg.BIZ_ERROR);
            }
            if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
                LOGGER.error("sessionId={},秒杀订单消息投递失败,下单失败.msgBody={},sendResult=null", sessionId, msgBody);
                return Result.error(CodeMsg.BIZ_ERROR);
            }
            ChargeOrderResponse chargeOrderResponse = new ChargeOrderResponse();
            BeanUtils.copyProperties(msgProtocol, chargeOrderResponse);
            LOGGER.info("sessionId={},秒杀订单消息投递成功,订单入队.出参chargeOrderResponse={},sendResult={}", sessionId, chargeOrderResponse.toString(), JSON.toJSONString(sendResult));
            return Result.success(CodeMsg.ORDER_INLINE, chargeOrderResponse);
        } catch (Exception e) {
            int sendRetryTimes = mqProducer.getRetryTimesWhenSendFailed();
            LOGGER.error("sessionId={},sendRetryTimes={},秒杀订单消息投递异常,下单失败.msgBody={},e={}", sessionId, sendRetryTimes, msgBody, LogExceptionWapper.getStackTrace(e));
        }
        return Result.error(CodeMsg.BIZ_ERROR);
    }

    /**
     * 查单前参数校验
     * @param queryOrderRequest
     * @param sessionId
     * @return
     */
    @Override
    public boolean checkParamsBeforeSecKillQuery(QueryOrderRequest queryOrderRequest, String sessionId) {
        // 入参校验
        if (queryOrderRequest == null) {
            LOGGER.info("sessionId={},查询请求参数queryOrderRequest为空,返回查询失败", sessionId);
            return false;
        }
        LOGGER.info("sessionId={},查询开始,查询请求参数queryOrderRequest=[{}].", sessionId, JSON.toJSONString(queryOrderRequest));

        String userPhoneNum = queryOrderRequest.getUserPhoneNum();
        String prodId = queryOrderRequest.getProdId();

        if (StringUtils.isBlank(prodId) || StringUtils.isBlank(userPhoneNum)) {
            LOGGER.info("sessionId={},查询必要参数为空,返回查询失败", sessionId);
            return false;
        }
        return true;
    }

    /**
     * 执行订单查询业务
     * @param queryOrderRequest
     * @param sessionId
     * @return
     */
    @Override
    public Result<QueryOrderResponse> queryOrder(QueryOrderRequest queryOrderRequest, String sessionId) {
        return orderQueryManager.queryOrder(queryOrderRequest, sessionId);
    }

}