package cn.axzo.msg.center.message.service.youmeng;

import cn.axzo.msg.center.api.request.MsgBody4Guest;
import cn.axzo.msg.center.common.utils.BizAssertions;
import cn.axzo.msg.center.dal.mapper.MessageBaseTemplateMapper;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate.PushData;
import cn.axzo.msg.center.event.outer.PushYouMengMessageHandler;
import cn.axzo.msg.center.event.payload.MessageHistoryUpdatedPayload.ActionPath;
import cn.axzo.msg.center.inside.notices.service.IYouMengMessageService;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.taobao.api.internal.util.NamedThreadFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static java.util.stream.Collectors.toList;

/**
 * @author yanglin
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class YoumengTemplateClient {

    private final IYouMengMessageService youMengMessageService;
    private final PushYouMengMessageHandler pushYouMengMessageHandler;
    private final MessageBaseTemplateMapper messageBaseTemplateMapper;

    private final ExecutorService executor = new ThreadPoolExecutor(
            30, 50,
            10, TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(10000),
            new NamedThreadFactory(getClass().getSimpleName()));

    public void asyncSend(Long templateId, List<YoumengPush> pushes) {
        try {
            executor.execute(() -> {
                try {
                    syncSend(templateId, pushes);
                } catch (Exception e) {
                    log.warn("Youmeng push error", e);
                }
            });
        } catch (RejectedExecutionException e) {
            log.warn("Youmeng is busy", e);
        }
    }

    public void syncSend(Long templateId, List<YoumengPush> pushes) {
        BizAssertions.assertNotNull(templateId, "模版id不能为空");
        BizAssertions.assertNotEmpty(pushes, "pushes不能为空");
        MessageBaseTemplate template = messageBaseTemplateMapper.selectById(templateId);
        if (template == null) {
            log.warn("Can't find template, templateId={}", templateId);
            return;
        }
        List<PushTerminalEnum> terminals = JSON.parseArray(template.getPushTerminal(), PushTerminalEnum.class);
        if (CollectionUtils.isEmpty(pushes)) {
            log.info("Skip sending push, because push terminals is empty.");
            return;
        }
        JSONObject pushCfgObj = template.getPushData();
        if (pushCfgObj == null) {
            log.info("Skip sending push because push configuration is missing. template={}", template);
            return;
        }
        PushData pushCfg = pushCfgObj.toJavaObject(PushData.class);
        if (!pushCfg.isSwitchOn()) {
            log.info("Skip sending push because push is turned off. template={}", template);
            return;
        }
        for (YoumengPush push : pushes) {
            for (PushTerminalEnum terminal : terminals) {
                if (terminal.toAppType() == null) {
                    log.warn("Can't determine app type, skip sending push. terminal is {}, template={}", terminal, template);
                    continue;
                }
                MsgBody4Guest request = MsgBody4Guest.builder()
                        .ty(0)
                        .f("0")
                        .appClient(terminal.toAppType().getCode())
                        .pushType(pushCfg.getType())
                        .m(push.getContent())
                        .m3(push.getReceiverPersonId() + "")
                        .m2(configurePlatforms(pushCfg, push))
                        // 为了兼容老版本，保证老版本的工人端能收到push，所以新的push都alias都是person
                        .t("not_identity" + push.getReceiverPersonId())
                        .ouId(push.determineReceiverOuId())
                        .build();
                youMengMessageService.sendPushMessage(request);
                log.info("push send success, template={}, request={}", template, request);
            }
        }
    }

    private String configurePlatforms(PushData pushData, YoumengPush push) {
        JSONObject jsonObject = new JSONObject()
                .fluentPut("t", push.getTitle())
                .fluentPut("type", 0);
        if (StringUtils.isNotBlank(pushData.getVoiceFile())) {
            jsonObject.fluentPut("audio", pushData.getVoiceFile());
        }

        if (push.getNavigations() != null) {
            List<ActionPath> paths = push.getNavigations().stream()
                    .map(p -> new ActionPath(p.getPlatform(), p.getUrl()))
                    .collect(toList());
            pushYouMengMessageHandler.resolveRouter(jsonObject, paths);
        }

        return jsonObject.toJSONString();
    }

}