package com.qmth.themis.business.service.impl;

import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.MqDto;
import com.qmth.themis.business.service.MqDtoService;
import com.qmth.themis.business.service.ProducerServer;
import com.qmth.themis.business.util.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Description: mqdto 服务实现类
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/7/2
 */
@Service
public class MqDtoServiceImpl implements MqDtoService {
    private final static Logger log = LoggerFactory.getLogger(MqDtoServiceImpl.class);

    @Resource
    ProducerServer producerServer;

    @Resource
    RedisUtil redisUtil;

    /**
     * 组装异步消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendAsyncMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.asyncMsg(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装同步消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendSyncMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.syncMsg(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装单向消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendOneWayMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.sendOneWay(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装异步延时消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendAsyncDelayMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.asyncDelayMsg(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装异步单向顺序消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendOneOrderMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.sendOneWayOrderly(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装异步顺序消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendAsyncOrderMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.asyncOrderlyMsg(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装同步顺序消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendSyncOrderMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.syncOrderlyMsg(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装同步延时消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendSyncDelayMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.syncDelayMsg(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 组装事务消息
     *
     * @param mqDto
     * @return
     */
    @Override
    public MqDto assembleSendTranMsg(MqDto mqDto) {
        mqDto.setAck(SystemConstant.DELIVERED_ACK_TYPE);
        try {
            producerServer.sendMsgTran(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {
                mqDto.setAck(SystemConstant.UNSEND_ACK_TYPE);
            }
        } finally {
            setTopicBuffer(mqDto);
        }
        return null;
    }

    /**
     * 构建mq延时消息
     *
     * @param level
     * @return
     */
    @Override
    public Map<String, Object> buildMqDelayMsg(String level) {
        Map<String, Object> tranMap = new HashMap<>();
        //发送延时mq消息start
        Integer time = SystemConstant.mqDelayLevel.get(level);
        LocalDateTime dt = LocalDateTime.now();
        if (level.contains("m")) {
            dt = dt.plusMinutes(Long.parseLong(level.replace("m", "")));
        } else if (level.contains("s")) {
            dt = dt.plusSeconds(Long.parseLong(level.replace("s", "")));
        } else if (level.contains("h")) {
            dt = dt.plusHours(Long.parseLong(level.replace("h", "")));
        }
        tranMap.put("timeOut", time);
        tranMap.put("mqExecTime", dt.toInstant(ZoneOffset.of("+8")).toEpochMilli());
        return tranMap;
    }

    /**
     * 设置mq buffer type
     *
     * @param mqDto
     */
    void setTopicBuffer(MqDto mqDto) {
        if (Objects.nonNull(mqDto)) {
            if (Objects.equals(mqDto.getType().getType(), "normal")) {
                redisUtil.set(SystemConstant.MQ_TOPIC_BUFFER_LIST, mqDto.getId(), mqDto);
            } else if (Objects.equals(mqDto.getType().getType(), "broadcast")) {
                redisUtil.set(SystemConstant.MQ_BROADCAST_TOPIC_BUFFER_LIST, mqDto.getId(), mqDto);
            } else if (Objects.equals(mqDto.getType().getType(), "delay")) {
                redisUtil.set(SystemConstant.MQ_DELAY_TOPIC_BUFFER_LIST, mqDto.getId(), mqDto);
            } else if (Objects.equals(mqDto.getType().getType(), "order")) {
                redisUtil.set(SystemConstant.MQ_ORDER_TOPIC_BUFFER_LIST, mqDto.getId(), mqDto);
            }
        }
    }
}
