package com.red.circle.other.app.common.cp;

import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.rds.entity.user.user.CpApply;
import com.red.circle.other.infra.enums.user.user.CpRelationshipType;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.json.JacksonUtils;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;

public final class CpRelationC2cNoticeUtils {

  public static final String NOTICE_TYPE = "CP_BUILD";
  public static final String ACTION_INVITE_PENDING = "INVITE_PENDING";
  public static final String ACTION_RELATION_ESTABLISHED = "RELATION_ESTABLISHED";
  public static final String ACTION_RELATION_REJECTED = "RELATION_REJECTED";
  public static final String ACTION_RELATION_EXPIRED = "RELATION_EXPIRED";

  private CpRelationC2cNoticeUtils() {
  }

  public static CustomC2cMsgBodyCmd buildInvitePending(Long fromUserId, Long toUserId,
      Long applyId, UserProfileDTO senderProfile, UserProfileDTO acceptProfile,
      boolean isReconcile, CpRelationshipType relationType, String title) {
    return buildInvitePendingMessage(fromUserId, toUserId, applyId, senderProfile, acceptProfile,
        isReconcile, relationType, title);
  }

  private static CustomC2cMsgBodyCmd buildInvitePendingMessage(Long fromUserId, Long toUserId,
      Long applyId, UserProfileDTO senderProfile, UserProfileDTO acceptProfile,
      boolean isReconcile, CpRelationshipType relationType, String title) {
    Map<String, Object> content = senderContent(senderProfile);
    content.put("applyType", isReconcile ? "RECONCILE" : "APPLY");
    content.put("relationType", relationType.name());
    putAcceptProfile(content, acceptProfile);
    long createTimeSeconds = System.currentTimeMillis() / 1000;
    long expireTimeSeconds = createTimeSeconds + TimeUnit.DAYS.toSeconds(1);
    content.put("createTime", createTimeSeconds);
    content.put("sendTime", createTimeSeconds);
    content.put("dismissEndTime", expireTimeSeconds);

    Map<String, Object> payload = basePayload(applyId, relationType.name(), title,
        ACTION_INVITE_PENDING, "PENDING", content);
    payload.put("createTime", createTimeSeconds);
    payload.put("sendTime", createTimeSeconds);
    payload.put("dismissEndTime", expireTimeSeconds);
    putSenderProfile(payload, senderProfile);
    putAcceptProfile(payload, acceptProfile);
    return buildMessage(fromUserId, toUserId, payload);
  }

  public static CustomC2cMsgBodyCmd buildAccepted(CpApply cpApply, UserProfile senderProfile,
      UserProfile acceptProfile) {
    return buildAccepted(cpApply, senderProfile, acceptProfile, cpApply.getAcceptApplyUserId(),
        cpApply.getSendApplyUserId());
  }

  public static CustomC2cMsgBodyCmd buildAcceptedToAcceptUser(CpApply cpApply,
      UserProfile senderProfile, UserProfile acceptProfile) {
    return buildAccepted(cpApply, senderProfile, acceptProfile, cpApply.getSendApplyUserId(),
        cpApply.getAcceptApplyUserId());
  }

  private static CustomC2cMsgBodyCmd buildAccepted(CpApply cpApply, UserProfile senderProfile,
      UserProfile acceptProfile, Long fromUserId, Long toUserId) {
    String relationType = CpRelationshipType.normalize(cpApply.getRelationType());
    String title = "User " + displayName(acceptProfile) + " accepted your "
        + relationType.toLowerCase() + " invitation.";
    Map<String, Object> content = senderContent(senderProfile);
    content.put("applyType", "APPLY");
    content.put("relationType", relationType);
    putAcceptProfile(content, acceptProfile);

    Map<String, Object> payload = basePayload(cpApply.getId(), relationType, title,
        ACTION_RELATION_ESTABLISHED, "ACCEPTED", content);
    payload.put("agree", true);
    putSenderProfile(payload, senderProfile);
    putAcceptProfile(payload, acceptProfile);
    return buildMessage(fromUserId, toUserId, payload);
  }

  public static CustomC2cMsgBodyCmd buildRejected(CpApply cpApply, UserProfile senderProfile,
      UserProfile acceptProfile) {
    return buildRejected(cpApply, senderProfile, acceptProfile, cpApply.getAcceptApplyUserId(),
        cpApply.getSendApplyUserId());
  }

  public static CustomC2cMsgBodyCmd buildRejectedToAcceptUser(CpApply cpApply,
      UserProfile senderProfile, UserProfile acceptProfile) {
    return buildRejected(cpApply, senderProfile, acceptProfile, cpApply.getSendApplyUserId(),
        cpApply.getAcceptApplyUserId());
  }

  private static CustomC2cMsgBodyCmd buildRejected(CpApply cpApply, UserProfile senderProfile,
      UserProfile acceptProfile, Long fromUserId, Long toUserId) {
    String relationType = CpRelationshipType.normalize(cpApply.getRelationType());
    String title = "User " + displayName(acceptProfile) + " declined your "
        + relationType.toLowerCase() + " invitation.";
    Map<String, Object> content = senderContent(senderProfile);
    content.put("applyType", "APPLY");
    content.put("relationType", relationType);
    putAcceptProfile(content, acceptProfile);

    Map<String, Object> payload = basePayload(cpApply.getId(), relationType, title,
        ACTION_RELATION_REJECTED, "REJECTED", content);
    payload.put("agree", false);
    putSenderProfile(payload, senderProfile);
    putAcceptProfile(payload, acceptProfile);
    return buildMessage(fromUserId, toUserId, payload);
  }

  public static CustomC2cMsgBodyCmd buildExpiredToAcceptUser(CpApply cpApply,
      UserProfile senderProfile, UserProfile acceptProfile) {
    return buildExpired(cpApply, senderProfile, acceptProfile, cpApply.getSendApplyUserId(),
        cpApply.getAcceptApplyUserId());
  }

  public static CustomC2cMsgBodyCmd buildExpiredToSendUser(CpApply cpApply,
      UserProfile senderProfile, UserProfile acceptProfile) {
    return buildExpired(cpApply, senderProfile, acceptProfile, cpApply.getAcceptApplyUserId(),
        cpApply.getSendApplyUserId());
  }

  private static CustomC2cMsgBodyCmd buildExpired(CpApply cpApply, UserProfile senderProfile,
      UserProfile acceptProfile, Long fromUserId, Long toUserId) {
    String relationType = CpRelationshipType.normalize(cpApply.getRelationType());
    String title = "Your " + relationType.toLowerCase() + " invitation expired.";
    Map<String, Object> content = senderContent(senderProfile);
    content.put("applyType", "APPLY");
    content.put("relationType", relationType);
    putAcceptProfile(content, acceptProfile);

    Map<String, Object> payload = basePayload(cpApply.getId(), relationType, title,
        ACTION_RELATION_EXPIRED, "EXPIRED", content);
    payload.put("expired", true);
    putSenderProfile(payload, senderProfile);
    putAcceptProfile(payload, acceptProfile);
    return buildMessage(fromUserId, toUserId, payload);
  }

  private static Map<String, Object> basePayload(Long applyId, String relationType, String title,
      String action, String status, Map<String, Object> content) {
    Map<String, Object> payload = new LinkedHashMap<>();
    payload.put("noticeType", NOTICE_TYPE);
    payload.put("type", NOTICE_TYPE);
    payload.put("noticeAction", action);
    payload.put("action", action);
    payload.put("status", status);
    payload.put("result", status);
    payload.put("state", status);
    payload.put("title", title);
    payload.put("content", JacksonUtils.toJson(content));
    payload.put("expand", applyId);
    payload.put("applyId", applyId);
    payload.put("relationType", relationType);
    return payload;
  }

  private static CustomC2cMsgBodyCmd buildMessage(Long fromUserId, Long toUserId,
      Map<String, Object> payload) {
    return CustomC2cMsgBodyCmd.builder()
        .fromAccount(fromUserId)
        .toAccount(toUserId)
        .desc(NOTICE_TYPE)
        .data(payload)
        .syncOtherMachine(1)
        .build();
  }

  private static Map<String, Object> senderContent(UserProfileDTO userProfile) {
    Map<String, Object> content = new LinkedHashMap<>();
    content.put("userId", userProfile.getId());
    content.put("senderUserId", userProfile.getId());
    content.put("userNickname", userProfile.getUserNickname());
    content.put("account", userProfile.getAccount());
    content.put("actualAccount", userProfile.actualAccount());
    content.put("userAvatar", userProfile.getUserAvatar());
    content.put("countryCode", userProfile.getCountryCode());
    content.put("countryName", userProfile.getCountryName());
    return content;
  }

  private static Map<String, Object> senderContent(UserProfile userProfile) {
    Map<String, Object> content = new LinkedHashMap<>();
    content.put("userId", Objects.nonNull(userProfile) ? userProfile.getId() : null);
    content.put("senderUserId", Objects.nonNull(userProfile) ? userProfile.getId() : null);
    content.put("userNickname", Objects.nonNull(userProfile) ? userProfile.getUserNickname() : null);
    content.put("account", Objects.nonNull(userProfile) ? userProfile.getAccount() : null);
    content.put("actualAccount", Objects.nonNull(userProfile) ? userProfile.getActualAccount() : null);
    content.put("userAvatar", Objects.nonNull(userProfile) ? userProfile.getUserAvatar() : null);
    content.put("countryCode", Objects.nonNull(userProfile) ? userProfile.getCountryCode() : null);
    content.put("countryName", Objects.nonNull(userProfile) ? userProfile.getCountryName() : null);
    return content;
  }

  private static void putSenderProfile(Map<String, Object> payload, UserProfileDTO userProfile) {
    payload.put("userId", userProfile.getId());
    payload.put("senderUserId", userProfile.getId());
    payload.put("account", userProfile.getAccount());
    payload.put("actualAccount", userProfile.actualAccount());
    payload.put("userNickname", userProfile.getUserNickname());
    payload.put("userAvatar", userProfile.getUserAvatar());
  }

  private static void putSenderProfile(Map<String, Object> payload, UserProfile userProfile) {
    if (Objects.isNull(userProfile)) {
      return;
    }
    payload.put("userId", userProfile.getId());
    payload.put("senderUserId", userProfile.getId());
    payload.put("account", userProfile.getAccount());
    payload.put("actualAccount", userProfile.getActualAccount());
    payload.put("userNickname", userProfile.getUserNickname());
    payload.put("userAvatar", userProfile.getUserAvatar());
  }

  private static void putAcceptProfile(Map<String, Object> payload, UserProfileDTO userProfile) {
    payload.put("acceptUserId", userProfile.getId());
    payload.put("acceptAccount", userProfile.getAccount());
    payload.put("acceptActualAccount", userProfile.actualAccount());
    payload.put("acceptNickname", userProfile.getUserNickname());
    payload.put("acceptUserNickname", userProfile.getUserNickname());
    payload.put("acceptUserAvatar", userProfile.getUserAvatar());
  }

  private static void putAcceptProfile(Map<String, Object> payload, UserProfile userProfile) {
    if (Objects.isNull(userProfile)) {
      return;
    }
    payload.put("acceptUserId", userProfile.getId());
    payload.put("acceptAccount", userProfile.getAccount());
    payload.put("acceptActualAccount", userProfile.getActualAccount());
    payload.put("acceptNickname", userProfile.getUserNickname());
    payload.put("acceptUserNickname", userProfile.getUserNickname());
    payload.put("acceptUserAvatar", userProfile.getUserAvatar());
  }

  private static String displayName(UserProfile userProfile) {
    if (Objects.isNull(userProfile)) {
      return "";
    }
    if (StringUtils.isNotBlank(userProfile.getUserNickname())) {
      return userProfile.getUserNickname();
    }
    if (StringUtils.isNotBlank(userProfile.getAccount())) {
      return userProfile.getAccount();
    }
    return Objects.toString(userProfile.getId(), "");
  }
}
