package cn.axzo.msg.center.notices.manager;

import cn.axzo.msg.center.api.request.AddMnsChannelRequest;
import cn.axzo.msg.center.dal.MNSMessageChannelDao;
import cn.axzo.msg.center.domain.entity.MNSMessageChannel;
import cn.axzo.msg.center.notices.common.constans.CommonConstants;
import cn.axzo.msg.center.notices.common.enums.MessageChannelEnum;
import cn.axzo.msg.center.notices.common.enums.ReturnCodeEnum;
import cn.axzo.msg.center.notices.common.exception.BizException;
import cn.axzo.msg.center.notices.manager.api.MessageChannelRouter;
import cn.axzo.msg.center.notices.manager.api.MessageTemplateManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * 消息渠道路由实现类
 *
 * @author zhaoyong_sh
 * @see MessageChannelRouteImpl
 * @since 2021-05-27 15:04
 */
@Slf4j
@Service("messageChannelRoute")
public class MessageChannelRouteImpl implements MessageChannelRouter {

    @Resource
    private MNSMessageChannelDao mnsMessageChannelDao;
    @Resource(name = "messageTemplateManager")
    private MessageTemplateManager messageTemplateManager;

    @Override
    public MNSMessageChannel route(String condition) {
        List<MNSMessageChannel> messageChannels = mnsMessageChannelDao.queryAvailable();

        BizException.error(CollectionUtils.isNotEmpty(messageChannels), ReturnCodeEnum.MESSAGE_CHANNEL_NOT_VALID);
        // 查询优先级最高的一个
        Optional<MNSMessageChannel> messageChannelOptional = messageChannels.stream()
                // 条件过滤
                .filter(messageChannel -> conditionFilter(condition, messageChannel))
                // 优先级越小,排在越前
                .min(Comparator.comparing(MNSMessageChannel::getPriority));
        return messageChannelOptional.orElse(null);
    }

    @Override
    public MNSMessageChannel route(String condition, String innerTemplateCode) {
        List<MNSMessageChannel> messageChannels = mnsMessageChannelDao.queryAvailable();
        BizException.error(CollectionUtils.isNotEmpty(messageChannels), ReturnCodeEnum.MESSAGE_CHANNEL_NOT_VALID);
        // 从内部短信模板与渠道短信模板映射表中查询生效的映射数据
        List<String> mappedChannelCodes = messageTemplateManager.listChannelCodes(innerTemplateCode);
        // 检测是否配置了有效的映射关系
        BizException.error(CollectionUtils.isNotEmpty(mappedChannelCodes), ReturnCodeEnum.MESSAGE_CHANNEL_NOT_VALID);
        final Set<String> pickChannelCodes = new HashSet<>(mappedChannelCodes);
        // 解析入参是否指定了渠道
        String specifyChannelCode = parseCondition(condition);
        if (pickChannelCodes.contains(specifyChannelCode)) {
            // 指定的渠道编码在映射关系中, 优先使用该渠道
            pickChannelCodes.clear();
            pickChannelCodes.add(specifyChannelCode);
        }
        // 查询优先级最高的一个
        return messageChannels.stream()
                // 条件过滤
                .filter(messageChannel -> pickChannelCodes.contains(messageChannel.getChannelCode()))
                // 优先级越小,排在越前
                .min(Comparator.comparing(MNSMessageChannel::getPriority))
                .orElse(null);
    }

    @Override
    public String addChannel(AddMnsChannelRequest request) {
        MNSMessageChannel savedChannel = mnsMessageChannelDao.lambdaQuery()
                .eq(MNSMessageChannel::getChannelCode, request.getChannelCode())
                .last("LIMIT 1")
                .one();
        BizException.error(savedChannel == null, ReturnCodeEnum.MESSAGE_CHANNEL_EXISTS);
        MNSMessageChannel channel = new MNSMessageChannel();
        channel.setChannelCode(request.getChannelCode());
        channel.setChannelName(request.getChannelName());
        channel.setPriority(request.getPriority());
        mnsMessageChannelDao.save(channel);
        return channel.getId() + "";
    }

    private String parseCondition(String condition) {
        if (StringUtils.isEmpty(condition)) {
            // 未指定渠道
            return null;
        }
        try {
            JSONObject conditionJO = JSON.parseObject(condition);
            // 指定路由渠道
            String channelCode = conditionJO.getString(CommonConstants.ASSIGN_CHANNEL);
            if (Objects.nonNull(MessageChannelEnum.getByCode(channelCode))) {
                return channelCode;
            }
        } catch (Exception e) {
            log.error("broke out some exception while parsing condition. condition:{}", condition, e);
        }
        return null;
    }

    private boolean conditionFilter(String condition, MNSMessageChannel messageChannel) {
        try {
            JSONObject conditionJO = JSON.parseObject(condition);
            // 指定路由渠道
            String channelCode = conditionJO.getString(CommonConstants.ASSIGN_CHANNEL);
            if (StringUtils.isNoneBlank(channelCode)) {
                MessageChannelEnum channelEnum = MessageChannelEnum.getByCode(channelCode);
                if (channelEnum != null) {
                    return channelCode.equals(messageChannel.getChannelCode());
                }
            }
            return true;
        } catch (Exception e) {
            return true;
        }
    }
}
