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

import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.im.center.api.feign.MessageApi;
import cn.axzo.im.center.api.vo.req.MessageInfo;
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.msg.center.common.exception.ServiceException;
import cn.axzo.msg.center.common.utils.PlaceholderResolver;
import cn.axzo.msg.center.dal.GeneralMessageRecordDao;
import cn.axzo.msg.center.domain.entity.GeneralMessageRecord;
import cn.axzo.msg.center.inside.notices.config.MessageSystemConfig;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO;
import cn.axzo.msg.center.message.domain.dto.SendImMessageDTO;
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
import cn.axzo.msg.center.message.service.GeneralMessageService;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.message.service.impl.oldmsg.OldMsgStatCache;
import cn.axzo.msg.center.service.dto.IdentityDTO;
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
import cn.axzo.msg.center.service.dto.PersonDTO;
import cn.axzo.msg.center.service.enums.GeneralMessageStateEnum;
import cn.axzo.msg.center.service.enums.IdentityTypeEnum;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import cn.axzo.msg.center.service.general.request.GeneralMessageOldDataStatisticRequest;
import cn.axzo.msg.center.service.general.request.GeneralMessageSendRequest;
import cn.axzo.msg.center.service.general.response.GeneralMessageOldDataStatisticResponse;
import cn.axzo.msg.center.utils.MessageRouterUtil;
import cn.axzo.msg.center.utils.UUIDUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author cold_blade
 * @date 2023/10/19
 * @version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GeneralMessageServiceImpl implements GeneralMessageService {

    private static final Integer ZERO = 0;

    private static final PersonDTO SYSTEM_SENDER = PersonDTO.builder()
            .id(0L)
            .identity(IdentityDTO.builder().id(0L).type(IdentityTypeEnum.NOT_SUPPORT).build())
            .build();

    private static final ImmutableMap<PushTerminalEnum, AppTypeEnum> PUSH_TERMINAL_APP_MAP = ImmutableMap.of(
            PushTerminalEnum.B_ENTERPRISE_APP, AppTypeEnum.CMP,
            PushTerminalEnum.C_WORKER_APP, AppTypeEnum.CM
    );

    private final MessageApi messageApi;
    private final MessageSystemConfig messageSystemConfig;
    private final GeneralMessageRecordDao generalMessageRecordDao;
    private final MessageTemplateNewService messageTemplateNewService;
    private final MessageRouterUtil messageRouterUtil;
    private final OldMsgStatCache oldMsgStatCache;
    private final PendingMessageBizConfig cfg;

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public List<SendImMessageDTO> batchSendMessage(GeneralMessageSendRequest request) {
        // 查询模板基础信息
        MessageTemplateDTO template = messageTemplateNewService.queryEnableTemplateByCode(request.getTemplateCode())
                .orElseThrow(() -> new ServiceException("未查询到对应的模板"));
        // 构建消息记录并存储
        List<GeneralMessageRecord> messageRecords = buildMessageRecord(request, template);
        generalMessageRecordDao.saveBatch(messageRecords);
        // 发送IM消息
        return pushImMessage(messageRecords, template);
    }

    @Override
    public GeneralMessageOldDataStatisticResponse statisticOldData(GeneralMessageOldDataStatisticRequest request) {
        if (cfg.isOldMsgOffline()) {
            return GeneralMessageOldDataStatisticResponse.builder()
                    .unreadCount(ZERO)
                    .latestMsgSendTimestamp(null)
                    .latestMsgContent(null)
                    .build();
        }
        return oldMsgStatCache.getCacheResponseOrReload(request);
    }

    private List<GeneralMessageRecord> buildMessageRecord(GeneralMessageSendRequest request, MessageTemplateDTO template) {
        return request.getReceiver().stream()
                .map(e -> buildMessageRecord(request, e, template))
                .collect(Collectors.toList());
    }

    private GeneralMessageRecord buildMessageRecord(GeneralMessageSendRequest request, PersonDTO receiver,
                                                    MessageTemplateDTO template) {
        PersonDTO sender = Objects.isNull(request.getSender()) ? SYSTEM_SENDER : request.getSender();
        return GeneralMessageRecord.builder()
                .identityCode(UUIDUtil.uuidString())
                .senderPersonId(sender.getId())
                .senderId(sender.getIdentity().getId())
                .senderType(sender.getIdentity().getType())
                .receiverPersonId(receiver.getId())
                .receiverId(receiver.getIdentity().getId())
                .receiverType(receiver.getIdentity().getType())
                .templateCode(template.getCode())
                .title(parseString(template.getTitle(), request.getBizExtParams()))
                .content(parseString(template.getContent(), request.getBizExtParams()))
                .orgType(request.getOrgType())
                .orgId(request.getOrgId())
                .orgName(request.getOrgName())
                .state(GeneralMessageStateEnum.HAS_BEEN_SENT)
                .bizCode(request.getBizCode())
                .routerParams(request.getRouterParams())
                .bizExtParams(request.getBizExtParams())
                .build();
    }

    private List<SendImMessageDTO> pushImMessage(List<GeneralMessageRecord> messageRecords, MessageTemplateDTO template) {
        if (CollectionUtils.isEmpty(template.getPushTerminals())) {
            // 模板未配置任何推送终端
            return Collections.emptyList();
        }
        GeneralMessageRecord record = messageRecords.get(0);
        List<AppTypeEnum> appTypes = template.getPushTerminals().stream()
                .map(PUSH_TERMINAL_APP_MAP::get).collect(Collectors.toList());
        GeneralMessagePushVO message = convert(record, template);
        MessageInfo msgInfo = new MessageInfo();
        msgInfo.setAppTypeList(appTypes);
        msgInfo.setToPersonIdList(Sets.newHashSet(messageRecords.stream()
                .map(e -> String.valueOf(e.getReceiverPersonId()))
                .collect(Collectors.toSet())));
        msgInfo.setMsgHeader(record.getTitle());
        msgInfo.setMsgContent(record.getContent());
        msgInfo.setMsgTemplateId(record.getTemplateCode());
        msgInfo.setMsgTemplateContent(JSON.toJSONString(message));
        // 扩展信息
        Map<String, String> ext = new HashMap<>();
        ext.put("minAppVersion", template.getMinAppVersion());
        if (Objects.nonNull(record.getOrgId()) && record.getOrgId() > 0L) {
            ext.put("workspaceId", record.getOrgId().toString());
        }
        msgInfo.setExtendsInfo(ext);

        ApiResult<List<MessageDispatchResp>> result = messageApi.sendMessage(msgInfo);
        if (result.isError() || CollectionUtils.isEmpty(result.getData())) {
            log.warn("failed to batch send im message. result:{}", result);
            return Collections.emptyList();
        }
        return result.getData().stream()
                .filter(MessageDispatchResp::sendSuccess)
                .map(SendImMessageDTO::from)
                .collect(Collectors.toList());
    }

    private GeneralMessagePushVO convert(GeneralMessageRecord record, MessageTemplateDTO template) {
        // 对应模板的路由列表
        MessageTemplateRouterDTO msgTemplateRouter = template.getMsgTemplateRouter();
        // 解析路由地址
        msgTemplateRouter = messageRouterUtil.parseAndConcatRouteUrl(template, msgTemplateRouter, record.getRouterParams());
        // 获取模板卡片信息
        List<MessageCardContentItemDTO> rawCardContentItems = template.getMsgCardContentItems();
        List<MessageCardContentItemDTO> cardContentItems = rawCardContentItems;
        if (CollectionUtils.isNotEmpty(rawCardContentItems) && Objects.nonNull(record.getBizExtParams())
                && !record.getBizExtParams().isEmpty()) {
            // 克隆，避免修改入参
            cardContentItems = cardContentItems.stream()
                    .map(MessageCardContentItemDTO::deepClone)
                    .collect(Collectors.toList());
            cardContentItems.forEach(e -> {
                String value = PlaceholderResolver.getDefaultResolver()
                        .resolveByMap(e.getValue(), record.getBizExtParams());
                e.setValue(value);
            });
        }
        return GeneralMessagePushVO
                .from(record, template.getIcon(), messageSystemConfig.getOrgIcon(), msgTemplateRouter, cardContentItems);
    }

    private String parseString(String string, JSONObject params) {
        if (Objects.isNull(params)) {
            return string;
        }
        return PlaceholderResolver.getDefaultResolver().resolveByMap(string, params);
    }

}
