package cn.axzo.msg.center.inside.notices.service.impl.v3;

import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.msg.center.api.request.v3.MessageSendReqV3;
import cn.axzo.msg.center.api.response.v3.MessageSendRespV3;
import cn.axzo.msg.center.common.utils.BizAssertions;
import cn.axzo.msg.center.domain.entity.BizEventMapping;
import cn.axzo.msg.center.domain.enums.Channels;
import cn.axzo.msg.center.inside.notices.service.MessageServiceV3;
import cn.axzo.msg.center.inside.notices.service.impl.v3.msg.MessageMappingProcessor;
import cn.axzo.msg.center.inside.notices.service.impl.v3.msg.TemplateMessage;
import cn.axzo.msg.center.inside.notices.service.impl.v3.todo.TodoMappingProcessor;
import cn.axzo.msg.center.inside.notices.utils.FunctionalTransactionTemplate;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.service.BizEventMappingService;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.service.bizevent.request.ReachDto;
import cn.axzo.msg.center.utils.UUIDUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @author yanglin
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageServiceV3Impl implements MessageServiceV3 {

    private final BizEventMappingService bizEventMappingService;
    private final MessageTemplateNewService messageTemplateNewService;
    private final FunctionalTransactionTemplate transactionTemplate;
    private final ApplicationContext beanFactory;

    @Override
    public MessageSendRespV3 send(MessageSendReqV3 req) {
        log.info("received sending message request. req={}", req);
        req.validate();
        BizEventMapping mapping = bizEventMappingService
                .getByBizCode(req.getBizEventMappingCode())
                .orElse(null);
        BizAssertions.assertNotNull(mapping, String.format(
                "找不到对应的事件映射: %s", req.getBizEventMappingCode()));
        //noinspection DataFlowIssue
        BizAssertions.assertNotEmpty(mapping.getReachConfig(), String.format(
                "业务事件映射%s无业务动作配置", req.getBizEventMappingCode()));
        String sendRequestNo = UUIDUtil.uuidString();
        List<EventMappingProcessor> processors = new ArrayList<>();
        for (ReachDto cfg : mapping.getReachConfig()) {
            MessageTemplateDTO template = messageTemplateNewService
                    .queryEnableTemplateByCode(cfg.getTemplateCode())
                    .orElseThrow(() -> new ServiceException(String.format(
                            "未查询到对应的模板, templateCode=%s", cfg.getTemplateCode())));
            if (Channels.NOTIFICATION.is(cfg.getCategory())) {
                // @Scope("prototype") -> we're good
                MessageMappingProcessor imProcessor = beanFactory.getBean(MessageMappingProcessor.class);
                imProcessor.setTemplate(new TemplateMessage(req, sendRequestNo, cfg, template));
                processors.add(imProcessor);
            } else if (Channels.PENDING.is(cfg.getCategory())) {
                // @Scope("prototype") -> we're good
                TodoMappingProcessor todoProcessor = beanFactory.getBean(TodoMappingProcessor.class);
                todoProcessor.setSendRequestNo(sendRequestNo);
                todoProcessor.setSendRequestV3(req);
                todoProcessor.setTemplate(template);
                todoProcessor.setReachConfig(cfg);
                processors.add(todoProcessor);
            }
        }

        transactionTemplate.exec(() -> processors.forEach(EventMappingProcessor::saveRecords));
        processors.forEach(EventMappingProcessor::maybeAsyncSend);
        MessageSendRespV3 resp = new MessageSendRespV3(sendRequestNo, new HashMap<>());
        processors.forEach(p -> resp.addResult(p.buildTemplateSendResult()));
        return resp;
    }

}