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

import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.im.center.api.vo.ApiChannel;
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.center.common.enums.YesOrNo;
import cn.axzo.maokai.api.util.Ref;
import cn.axzo.msg.center.common.utils.BizAssertions;
import cn.axzo.msg.center.domain.entity.Card;
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
import cn.axzo.msg.center.message.service.card.domain.CardGroup;
import cn.axzo.msg.center.message.service.card.domain.CardSendModel;
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Parser;
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Service;
import cn.axzo.msg.center.message.service.impl.v3.UrlParser;
import cn.axzo.msg.center.nimpush.NimPushService;
import cn.axzo.msg.center.nimpush.PushPeer;
import cn.axzo.msg.center.nimpush.device.PushDeviceSnapshots;
import cn.axzo.msg.center.nimpush.payload.intent.Intent;
import cn.axzo.msg.center.push.PushData;
import cn.axzo.msg.center.service.domain.card.AppVersionConfig;
import cn.axzo.msg.center.service.dto.PeerPerson;
import cn.axzo.msg.center.service.enums.MessageChannel;
import cn.axzo.msg.center.service.pending.request.CardContent;
import cn.axzo.msg.center.service.pending.request.CardStateInfo;
import cn.axzo.msg.center.service.pending.response.v3.ParsedModel3Visitor;
import cn.axzo.msg.center.service.pending.response.v3.ParsedModelV3Walker;
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedModelV3;
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedTemplateV3;
import cn.axzo.msg.center.utils.UUIDUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;

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

    public static final String BIZ_ID_PREFIX = "msg-center";

    private final ModelV3Service modelV3Service;
    private final ModelV3Parser modelV3Parser;
    private final CardParser cardParser;
    private final NimPushService nimPushService;

    public static String getBizIdPrefix(String templateCode) {
        return String.format("%s:%s", BIZ_ID_PREFIX, templateCode);
    }

    void buildCardsForSend(CardSendModel sendModel) {
        GeneralMessagePushVO cardContent = cardParser.parseCardContent(
                sendModel.getCardTemplate(), sendModel.getRequest());
        sendModel.setCardContent(cardContent);
        for (PeerPerson person : sendModel.getRequest().getReceivers()) {
            for (AppTypeEnum appType : sendModel.getCardTemplate().ensureAppTypesPresent()) {
                Card card = new Card();
                sendModel.addCard(card);
                card.setBatchNo(sendModel.getRequestContext().getBatchNo());
                card.setAppCode(sendModel.getRequest().getAppCode());
                card.setImTaskId(0L);
                card.setBizMessageId("");
                card.setIdentityCode(UUIDUtil.uuidString());
                card.setBizCode(sendModel.getRequest().determineBizCode());
                card.setSubBizCode(sendModel.getRequest().getSubBizCode());
                card.setTemplateCode(sendModel.getRequest().getTemplateCode());
                CardStateInfo stateInfo = sendModel.getRequest().getStateInfo();
                card.setBizState(stateInfo.getBizState());
                card.setCardState(stateInfo.getCardState());
                card.setTitle(sendModel.getTemplate().getTitle());
                card.setContent(sendModel.getTemplate().getContent());
                card.setCardContent(cardContent);
                card.setBizParam(sendModel.getRequest().getBizParam());
                card.setRouterParam(sendModel.getRequest().getRouterParam());
                card.setSenderAppType(AppTypeEnum.SYSTEM);
                card.setIsSenderRobot(YesOrNo.YES);
                card.setReceiverAppType(appType);
                card.setSenderPersonId(sendModel.getRequest().getSender().getPersonId());
                card.setSenderOuId(sendModel.getRequest().getSender().getOuId());
                card.setSenderWorkspaceId(sendModel.getRequest().getSender().getWorkspaceId());
                card.setReceiverPersonId(person.getPersonId());
                card.setReceiverOuId(person.getOuId());
                card.setReceiverWorkspaceId(person.getWorkspaceId());
                card.setSubtitle(sendModel.getRequest().getSubtitle());
                card.setButtonStates(Collections.emptyList());
                card.setUpdatable(sendModel.getCardTemplate().isUpdatable() ? YesOrNo.YES : YesOrNo.NO);
            }
        }
    }

    SendTemplateMessageParam buildImSendRequest(CardSendModel sendModel,
                                                CardGroup group,
                                                PushDeviceSnapshots deviceSnapshots,
                                                String imSenderAccount) {
        ParsedTemplateV3 template = sendModel.getTemplate();
        Supplier<String> payloadBuilder = () -> {
            PushPeer peer = new PushPeer();
            peer.setSenderImAccount(imSenderAccount);
            peer.setOuId(group.getGroupKey().getOuId());
            peer.setWorkspaceId(group.getGroupKey().getWorkspaceId());
            peer.setAppType(group.getGroupKey().getAppType());
            peer.setApiChannel(ApiChannel.COMMON_MESSAGE);
            return nimPushService.buildPayloadString(sendModel.getParsedModel(), peer);
        };
        Supplier<JSONObject> extBuilder = () -> {
            JSONObject ext = new JSONObject();
            ext.put("minAppVersion", determineMinAppVersion(
                    sendModel.getParsedModel(), group.getGroupKey().getAppType()));
            if (group.getGroupKey().getOuId() != null)
                ext.put("ouId", String.valueOf(group.getGroupKey().getOuId()));
            if (group.getGroupKey().getWorkspaceId() != null)
                ext.put("workspaceId", String.valueOf(group.getGroupKey().getWorkspaceId()));
            return ext;
        };
        PushData pushData = template.parsePushData();
        SendTemplateMessageParam imRequest = new SendTemplateMessageParam();
        imRequest.setSender(null);
        imRequest.setMsgHeader(template.getTitle());
        imRequest.setMsgContent(template.getContent());
        imRequest.setMsgTemplateId(template.getCode());
        imRequest.setSendPriority(template.determineImSendPriority());
        imRequest.setMsgTemplateContent(JSON.toJSONString(sendModel.getCardContent()));
        imRequest.setBizId(String.format("%s:%s", getBizIdPrefix(
                template.getCode()), sendModel.getRequest().determineBizCode()));
        imRequest.setReceivePersons(group.buildReceiverAccounts());
        imRequest.setExt(extBuilder.get());
        imRequest.setUpdatable(sendModel.getCardTemplate().isUpdatable());
        if (pushData.determinePushable(log, template.getCode())) {
            imRequest.setPayload(payloadBuilder.get());
            imRequest.setExcludePushPayloads(group.buildNimPushExcludes(deviceSnapshots));
            if (StringUtils.isNotBlank(pushData.getVoiceFile()))
                imRequest.getExt().put(Intent.INTENT_SOUND, pushData.getVoiceFile());
        }
        return imRequest;
    }

    private String determineMinAppVersion(ParsedModelV3 model,
                                          AppTypeEnum appType) {
        Ref<String> minVersion = Ref.create("");
        ParsedModelV3Walker.walkDown(model, new ParsedModel3Visitor() {
            @Override
            public void visitAppVersionConfig(AppVersionConfig cfg) {
                if (cfg.getAppType() == appType)
                    minVersion.set(cfg.getMinVersion());
            }
        });
        return minVersion.get();
    }

    TemplateModelV3 ensureImChannelPresent(String templateCode) {
        TemplateModelV3 templateModel = modelV3Service.findEnabledByCode(templateCode).orElse(null);
        BizAssertions.assertNotNull(templateModel, "模板不存在或已下线 {} ", templateCode);
        //noinspection DataFlowIssue
        List<MessageChannel> channels = templateModel.getTemplate().determineChannels();
        BizAssertions.assertTrue(channels.contains(MessageChannel.IM),
                "模版未配置IM通道 {} ", templateModel.getTemplateCode());
        return templateModel;
    }

    CardTemplate parseCardTemplate(TemplateModelV3 templateModel, CardContent card) {
        ParsedModelV3 parsedModelV3 = modelV3Parser.parseModel(
                templateModel, card.getBizParam(), new UrlParser(card.getRouterParam()));
        return CardTemplate.wrap(parsedModelV3);
    }

}