package com.njcn.msgpush.module.push.service.message;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.msgpush.framework.common.util.object.PageUtils;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
import com.njcn.msgpush.module.push.client.sender.Sender;
import com.njcn.msgpush.module.push.constant.MessageStatusConstant;
import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import com.njcn.msgpush.module.push.dal.mysql.message.MessageRecordMapper;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class MessageRecordServiceImpl extends ServiceImpl<MessageRecordMapper, MessageRecordDO> implements MessageRecordService {

    @Autowired
    private Sender sender;

    @Autowired
    public ChannelProviderConfigService channelProviderConfigService;

    @Autowired
    @Qualifier("messageProviderFactoryMap")
    private Map<String, MessageProviderFactory> messageProviderFactoryMap;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean send(List<MessageRecordReqVO> reqVOList) {
        List<MessageRecordDO> messageRecordDOList = BeanUtil.copyToList(reqVOList, MessageRecordDO.class);
        messageRecordDOList.forEach(messageRecordDO -> {
            messageRecordDO.setStatus(MessageStatusConstant.PENDING);
        });
        this.saveBatch(messageRecordDOList);

        boolean sendResult = true;
        for (MessageRecordDO messageRecordDO : messageRecordDOList) {
            sendResult &= this.processSendMsg(messageRecordDO);
        }
        return sendResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean processSendMsg(MessageRecordDO messageRecordDO) {
        ChannelProviderConfigDO channelProviderConfigDO = channelProviderConfigService.getByTypeAndChannel(messageRecordDO.getProviderType(), messageRecordDO.getChannel());
        MessageProviderFactory messageProviderFactory = messageProviderFactoryMap.get(messageRecordDO.getProviderType());
        if (ObjectUtil.isNull(messageProviderFactory)) {
            throw new RuntimeException("暂不支持该供应商或者该供应商未激活：" + messageRecordDO.getProviderType());
        }
        boolean sendResult = switch (messageRecordDO.getChannel()) {
            case MsgPushConstant.CHANNEL_SMS -> messageProviderFactory.createSmsSender(channelProviderConfigDO, sender).sendSms(messageRecordDO);
            case MsgPushConstant.CHANNEL_EMAIL ->
                    messageProviderFactory.createEmailSender(channelProviderConfigDO, sender).sendEmail(messageRecordDO, new HashMap<>());
            case MsgPushConstant.CHANNEL_APP_PUSH -> messageProviderFactory.createAppPushSender(channelProviderConfigDO, sender).appPush(messageRecordDO);
            default -> throw new RuntimeException("暂不支持该渠道：" + messageRecordDO.getChannel());
        };

        this.updateStatus(messageRecordDO.getMessageId(), sendResult ? MessageStatusConstant.SUCCESS : MessageStatusConstant.FAILED);
        return sendResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(String messageId, String status) {
        return this.lambdaUpdate().eq(MessageRecordDO::getMessageId, messageId).set(MessageRecordDO::getStatus, status).update();
    }

    @Override
    public MessageRecordDO getById(String messageId) {
        return this.lambdaQuery().eq(MessageRecordDO::getMessageId, messageId).eq(MessageRecordDO::getDeleted, true).one();
    }

    @Override
    public boolean add(MessageRecordReqVO messageRecordSendReqVO) {
        MessageRecordDO messageRecordDO = BeanUtil.copyProperties(messageRecordSendReqVO, MessageRecordDO.class);
        return this.save(messageRecordDO);
    }

    @Override
    public List<MessageRecordDO> listByIds(Collection<? extends Serializable> ids) {
        return this.baseMapper.selectByIds(ids);
    }

    @Override
    public Page<MessageRecordDO> getPage(MessageRecordReqVO reqVO) {
        QueryWrapper<MessageRecordDO> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(StrUtil.isNotBlank(reqVO.getChannel()), MessageRecordDO::getChannel, reqVO.getChannel())
                .eq(StrUtil.isNotBlank(reqVO.getProviderType()), MessageRecordDO::getProviderType, reqVO.getProviderType())
                .eq(StrUtil.isNotBlank(reqVO.getAppName()), MessageRecordDO::getAppName, reqVO.getAppName());
        return this.page(new Page<>(PageUtils.getPageNum(reqVO), PageUtils.getPageSize(reqVO)), wrapper);
    }

    @Override
    public boolean update(MessageRecordReqVO reqVO) {
        MessageRecordDO messageRecordDO = BeanUtil.copyProperties(reqVO, MessageRecordDO.class);
        return this.updateById(messageRecordDO);
    }

    @Override
    public boolean delete(List<String> ids) {
        return this.lambdaUpdate().set(MessageRecordDO::getDeleted, false).update();
    }
}
