package cn.axzo.msg.center.nimpush;

import cn.axzo.im.center.api.vo.ApiChannel;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.msg.center.common.utils.BizAssertions;
import cn.axzo.msg.center.nimpush.payload.PushPayloadBuilder;
import cn.axzo.msg.center.nimpush.payload.intent.Intent;
import cn.axzo.msg.center.nimpush.payload.intent.IntentValue;
import cn.axzo.msg.center.push.PushData;
import cn.axzo.msg.center.push.PushMessage;
import cn.axzo.msg.center.service.domain.UrlConfig;
import cn.axzo.msg.center.service.domain.UrlConfigVisitor;
import cn.axzo.msg.center.service.domain.UrlConfigWalker;
import cn.axzo.msg.center.service.domain.url.AppUrl;
import cn.axzo.msg.center.service.enums.CodeDefinition;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;

import java.util.function.Consumer;

/**
 * @author yanglin
 */
@Service
public class NimPushService {

    private final PushPayloadBuilder<?>[] payloadBuilders;

    @SuppressWarnings("rawtypes")
    public NimPushService(ObjectProvider<PushPayloadBuilder[]> payloadBuilders) {
        this.payloadBuilders = payloadBuilders.getIfAvailable();
    }

    public String buildPayloadString(PushMessage message, PushPeer peer) {
        JSONObject payload = buildPayload(message, peer);
        return payload == null ? null : payload.toJSONString();
    }

    private JSONObject buildPayload(PushMessage message, PushPeer peer) {
        PushData pushData = message.getPushData();
        if (pushData == null || !pushData.isSwitchOn()) return null;
        PushContent content = new PushContent();
        content.setTitle(message.getPushTitle());
        content.setContent(message.getPushContent());
        content.setCustomSoundFile(pushData.getVoiceFile());
        content.setAppType(peer.getAppType());
        content.setMessageTye(CodeDefinition
                .findByCode(PushMessageTye.class, pushData.getType())
                .orElse(null));
        content.setCustomSoundFile(pushData.getVoiceFile());
        if (peer.getApiChannel() == ApiChannel.CUSTOM_MESSAGE)
            populateUrl(content, message.getPushUrl(), peer.getAppType());
        return buildPayload(content, peer);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    private JSONObject buildPayload(PushContent content, PushPeer peer) {
        Consumer<Intent<?>> intentPopulator = intent -> {
            intent.setValue(Intent.INTENT_TYPE,
                    peer.getApiChannel() == ApiChannel.CUSTOM_MESSAGE
                            ? IntentValue.TYPE_SERVER
                            : IntentValue.TYPE_IM);
            intent.setValue(Intent.INTENT_SESSION_TYPE, IntentValue.CONSTANT_SESSION_TYPE);
            intent.setValue(Intent.INTENT_SESSION_ID, IntentValue.create(peer.getSenderImAccount()));
            if (peer.getOuId() != null && peer.getOuId() != 0L)
                intent.setValue(Intent.INTENT_OU_ID, IntentValue.create(peer.getOuId()));
            if (peer.getWorkspaceId() != null && peer.getWorkspaceId() != 0L)
                intent.setValue(Intent.INTENT_WORKSPACE_ID, IntentValue.create(peer.getWorkspaceId()));
            if (StringUtils.isNotBlank(content.getCustomSoundFile()))
                intent.setValue(Intent.INTENT_SOUND, IntentValue.create(content.getCustomSoundFile()));
        };
        JSONObject payload = new JSONObject();
        payload.put("pushTitle", content.getTitle());
        for (PushPayloadBuilder builder : payloadBuilders) {
            Intent intent = builder.createIntent(content, peer);
            BizAssertions.assertNotNull(intent, "intent can't be null");
            intentPopulator.accept(intent);
            builder.build(content, intent, payload);
        }
        return payload;
    }

    private void populateUrl(PushContent content,
                             UrlConfig url,
                             AppTypeEnum appType) {
        if (url == null || appType == null) return;
        UrlConfigWalker.walkDown(url, new UrlConfigVisitor() {
            @Override
            public void visitAppManagerAndroid(AppUrl android) {
                if (android.hasUrl() && appType == AppTypeEnum.CMP)
                    content.setAndroidPushUrl(android.getUrl());
            }

            @Override
            public void visitAppManagerIos(AppUrl ios) {
                if (ios.hasUrl() && appType == AppTypeEnum.CMP)
                    content.setIosPushUrl(ios.getUrl());
            }

            @Override
            public void visitAppWorkerAndroid(AppUrl android) {
                if (android.hasUrl() && appType == AppTypeEnum.CM)
                    content.setAndroidPushUrl(android.getUrl());
            }

            @Override
            public void visitAppWorkerIos(AppUrl ios) {
                if (ios.hasUrl() && appType == AppTypeEnum.CM)
                    content.setIosPushUrl(ios.getUrl());
            }
        });
    }

}