package com.red.circle.external.infra.common;

import com.alibaba.fastjson.JSON;
import com.red.circle.component.instant.msg.tencet.notice.official.NoticeExtParam;
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.account.ImMessageManagerService;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateAbstract;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateCustomizeCmd;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateTypeCmd;
import com.red.circle.external.inner.model.enums.message.OfficialNoticeTypeEnum;
import com.red.circle.framework.web.util.ValidatorUtils;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.tool.core.tuple.ImmutableKeyValuePair;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;


/**
 * 官方消息服务.
 *
 * @author pengliang on 2023/7/12
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class OfficialNoticeCommonService {

  private final UserProfileClient userProfileClient;
  private final ImMessageManagerService imMessageManagerService;

  public void send(NoticeExtTemplateAbstract cmd) {
    log.info("sendNotice:{}", cmd);
    if (Objects.isNull(cmd)) {
      throw new IllegalArgumentException("cmd param error.");
    }

    if (CollectionUtils.isEmpty(cmd.getToAccounts())) {
      throw new IllegalArgumentException("cmd.accounts is empty.");
    }

    // 发送单个用户
    if (Objects.equals(cmd.getToAccounts().size(), 1)) {
      Long toAccount = cmd.getToAccounts().get(0);
      send(toAccount, toNoticeExtParam(getUserLocale(toAccount, cmd.getLangCode()), cmd));
      return;
    }

    // 发送一组相同语言用户
    if (StringUtils.isNotBlank(cmd.getLangCode())) {
      sendBatch(cmd.getToAccounts(), toNoticeExtParam(parseLocale(cmd.getLangCode()), cmd));
      return;
    }

    // 匹配用户语言分批发送
    Map<Long, String> userLangeMap = userProfileClient.mapLanguage(
        new HashSet<>(cmd.getToAccounts())).getBody();

    if (CollectionUtils.isEmpty(userLangeMap)) {
      sendBatch(cmd.getToAccounts(), toNoticeExtParam(Locale.ENGLISH, cmd));
      return;
    }

    Map<String, List<ImmutableKeyValuePair<Long, String>>> groupLangUser = userLangeMap.entrySet()
        .stream().map(entry -> ImmutableKeyValuePair.of(entry.getKey(), entry.getValue()))
        .collect(Collectors.groupingBy(ImmutableKeyValuePair::getValue));

    groupLangUser.forEach((key, val) ->
        sendBatch(val.stream().map(ImmutableKeyValuePair::getKey).toList(),
            toNoticeExtParam(parseLocale(key), cmd))
    );

  }

  public void send(Long toAccount, String langCode, OfficialNoticeTypeEnum noticeType) {
    send(NoticeExtTemplateTypeCmd.builder()
        .toAccount(toAccount)
        .langCode(langCode)
        .noticeType(noticeType)
        .build());
  }


  public void send(Long toAccount, String langCode, OfficialNoticeTypeEnum noticeType,
      Object templateParam) {
    send(NoticeExtTemplateTypeCmd.builder()
        .toAccount(toAccount)
        .langCode(langCode)
        .noticeType(noticeType)
        .templateParam(templateParam)
        .build());
  }

  public NoticeExtParam getNoticeExtParam(Long toAccount, String langCode,
      OfficialNoticeTypeEnum officialNoticeTypeEnum, Object templateParam, Object expand) {
    Locale locale = getUserLocale(toAccount, langCode);
    return NoticeExtParam.builder()
        .id(getId(null))
        .noticeType(officialNoticeTypeEnum.name())
        .title(officialNoticeTypeEnum.getTileFormat(locale, templateParam))
        .content(officialNoticeTypeEnum.getBodyFormat(locale, templateParam))
        .expand(expand)
        .build();
  }

  private void send(Long toAccount, NoticeExtParam noticeExtParam) {
    imMessageManagerService
        .sendCustomizeMessage(toAccount, noticeExtParam.getTitle(), noticeExtParam)
        .subscribe(res -> log.warn("sendNotice response result:{}", res),
            er -> log.error("sendNotice error【{}】 :{}", noticeExtParam, er));
  }

  private void sendBatch(List<Long> toAccounts, NoticeExtParam noticeExtParam) {
    if (CollectionUtils.isEmpty(toAccounts)) {
      return;
    }
    imMessageManagerService
        .sendCustomizeBatchMessage(distinct(toAccounts), noticeExtParam.getTitle(), noticeExtParam)
        .subscribe(res -> log.warn("sendBatch res:{}", res),
            err -> log.error("sendBatch error:{}", err));
  }

  private Locale getUserLocale(Long userId, String locale) {
    return parseLocale(
        StringUtils.isBlank(locale)
            ? userProfileClient.getLanguage(userId).getBody()
            : locale
    );
  }

  private Locale parseLocale(String locale) {
    return StringUtils.isBlank(locale) ? Locale.ENGLISH
        : org.springframework.util.StringUtils.parseLocale(locale);
  }


  private List<Long> distinct(List<Long> toAccounts) {
    return toAccounts.stream().distinct().collect(Collectors.toList());
  }

  private NoticeExtParam toNoticeExtParam(Locale locale, NoticeExtTemplateAbstract cmd) {

    if (!ValidatorUtils.validateFastPass(cmd)) {
      throw new IllegalArgumentException("required param not set.");
    }

    if (cmd instanceof NoticeExtTemplateTypeCmd typeCmd) {

      OfficialNoticeTypeEnum noticeTypeEnum = OfficialNoticeTypeEnum.valueOf(
          cmd.getNoticeType());

      String title = Objects.nonNull(typeCmd.getTemplateParam())
          ? noticeTypeEnum.getTileFormat(locale, typeCmd.getTemplateParam())
          : noticeTypeEnum.getTitle(locale);

      String content = Objects.nonNull(typeCmd.getTemplateParam())
          ? JSON.toJSONString(typeCmd.getTemplateParam())
          : "";

      return NoticeExtParam.builder()
          .id(getId(cmd))
          .noticeType(noticeTypeEnum.name())
          .title(title)
          .content(content)
          .expand(cmd.getExpand())
          .build();
    }

    if (cmd instanceof NoticeExtTemplateCustomizeCmd customizeCmd) {
      return NoticeExtParam.builder()
          .id(getId(cmd))
          .noticeType(customizeCmd.getNoticeType())
          .title(customizeCmd.getTitle())
          .content(customizeCmd.getContent())
          .expand(cmd.getExpand())
          .build();
    }

    throw new IllegalArgumentException("type error.");
  }

  private long getId(NoticeExtTemplateAbstract cmd) {
    return Objects.nonNull(cmd) && Objects.nonNull(cmd.getId())
        ? cmd.getId()
        : IdWorkerUtils.getId();
  }
}
