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

import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam.ReceivePerson;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.msg.center.api.enums.MsgStateV3Enum;
import cn.axzo.msg.center.api.request.v3.MessageSendReqV3;
import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.common.utils.PlaceholderResolver;
import cn.axzo.msg.center.domain.entity.MessageRecordV3;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
import cn.axzo.msg.center.service.bizevent.request.ReachDto;
import cn.axzo.msg.center.service.dto.PersonV3DTO;
import cn.axzo.msg.center.service.enums.OrganizationTypeEnum;
import cn.axzo.msg.center.utils.UUIDUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

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

/**
 * @author yanglin
 */
@RequiredArgsConstructor
public class TemplateMessage {

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

    private final MessageSendReqV3 req;
    private final String batchNo;
    @Getter
    private final ReachDto config;
    @Getter
    private final MessageTemplateDTO template;

    private List<MessageRecordV3> records;
    private String title;
    private String content;

    String getTemplateCode() {
        return template.getCode();
    }

    Collection<Long> getMessageIds() {
        return getMessageRecords().stream()
                .map(MessageRecordV3::getId)
                .collect(toSet());
    }

    Collection<Long> getReceiverPersonIds() {
        return getMessageRecords().stream()
                .map(MessageRecordV3::getReceiverPersonId)
                .collect(toList());
    }

    List<MessageRecordV3> getMessageRecords() {
        if (records != null) {
            return records;
        }
        records = new ArrayList<>();
        for (PersonV3DTO receiver : req.distinctReceivers()) {
            PersonV3DTO sender = req.getSender();
            MessageRecordV3 message = new MessageRecordV3();
            records.add(message);
            message.setBatchNo(batchNo);
            message.setIdentityCode(UUIDUtil.uuidString());
            message.setSenderPersonId(sender == null ? null : sender.getId());
            message.setSenderOuId(req.getSenderOuId());
            message.setSenderWorkspaceId(req.getSenderWorkspaceId());
            message.setReceiverPersonId(receiver.getId());
            message.setReceiverOuId(req.determineReceiversOuId());
            message.setReceiverWorkspaceId(req.determineReceiversWorkspaceId());
            message.setBizEventMappingCode(req.getBizEventMappingCode());
            message.setTemplateCode(template.getCode());
            message.setTitle(parseTitle());
            message.setContent(parseContent());
            OrganizationTypeEnum orgType = req.getReceiversOrgType();
            if (orgType == null) {
                orgType = OrganizationTypeEnum.UNKNOWN;
            }
            message.setReceiverOrgType(orgType.stringCode());
            message.setSubtitle(req.getSubtitle());
            message.setState(MsgStateV3Enum.UNSENT);
            message.setBizCode(req.determineBizCode());
            message.setRouterParams(req.getRouterParams());
            message.setBizExtParams(req.getBizExtParams());
            message.setMsgExtInfo(getMsgExtInfo());
            message.setFailCause(null);
            message.setCreateAt(new Date());
            message.setUpdateAt(new Date());
            message.setIsDelete(TableIsDeleteEnum.NORMAL.value);
            // 这里不设置发送时间, 有发送结果的时候再设置, 比较准确
        }
        return records;
    }

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

    SendTemplateMessageParam buildImRequest(MessageTemplateParser templateParser, List<AppTypeEnum> apps) {
        MessageRecordV3 sample = getMessageRecords().get(0);
        GeneralMessagePushVO sendVo = templateParser.parse(sample, template);

        SendTemplateMessageParam imReq = new SendTemplateMessageParam();
        imReq.setBizId(String.format("%s:%s", getBizIdPrefix(template.getCode()), req.determineBizCode()));
        imReq.setSendPriority(template.determineImSendPriority());
        imReq.setMsgHeader(parseTitle());
        imReq.setMsgContent(parseContent());
        imReq.setMsgTemplateId(template.getCode());
        imReq.setMsgTemplateContent(JSON.toJSONString(sendVo));
        // 接收人
        ArrayList<ReceivePerson> receivers = new ArrayList<>();
        Set<Long> cmUnique = new HashSet<>();
        Set<OuAndPerson> cmpUnique = new HashSet<>();
        for (PersonV3DTO receiver : req.receivers()) {
            PersonV3DTO.ReceiveModel imReceiveModel = receiver.getImReceiveModel();
            Long ouId = imReceiveModel == null ? req.determineReceiversOuId() : imReceiveModel.getOuId();
            for (AppTypeEnum app : apps) {
                if (app == AppTypeEnum.CM && !cmUnique.add(receiver.getId())) {
                    continue;
                }
                if (app == AppTypeEnum.CMP && !cmpUnique.add(new OuAndPerson(ouId, receiver.getId()))) {
                    continue;
                }
                receivers.add(new ReceivePerson(String.valueOf(receiver.getId()), ouId, app));
            }
        }
        imReq.setReceivePersons(receivers);
        // 扩展信息
        JSONObject ext = new JSONObject();
        ext.put("minAppVersion", template.getMinAppVersion());
        if (sample.getReceiverWorkspaceId() != null) {
            ext.put("workspaceId", String.valueOf(sample.getReceiverWorkspaceId()));
        }
        if (sample.getReceiverOuId() != null) {
            ext.put("ouId", String.valueOf(sample.getReceiverOuId()));
        }
        imReq.setExt(ext);
        return imReq;
    }

    // ------------------------------- 辅助方法

    String parseTitle() {
        if (title == null) {
            title = PlaceholderResolver.tryResolve(template.getTitle(), req.getBizExtParams());
        }
        return title;
    }

    String parseContent() {
        if (content == null) {
            content = PlaceholderResolver.tryResolve(template.getContent(), req.getBizExtParams());
        }
        return content;
    }

    /**
     * 预留
     */
    JSONObject getMsgExtInfo() {
        return new JSONObject();
    }

    @Data
    private static class OuAndPerson {
        private final Long ouId;
        private final Long personId;
    }

    @Override
    public String toString() {
        HashMap<String, Object> values = new HashMap<>();
        values.put("batchNo", batchNo);
        values.put("bizEventMappingCode", req.getBizEventMappingCode());
        values.put("bizCode", req.getBizCode());
        values.put("templateCode", template.getCode());
        values.put("messageIds", getMessageIds());
        values.put("receiverPersonIds", getReceiverPersonIds());
        return JSON.toJSONString(values);
    }
}