package com.red.circle.other.app.command.user.query;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.red.circle.common.business.core.enums.CommonErrorEnum;
import com.red.circle.common.business.dto.cmd.UserIdCommonCmd;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.convertor.user.UserCpCabinConvertor;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpCabinConfigCO;
import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpPairUserProfileCO;
import com.red.circle.other.app.dto.clientobject.user.relation.cp.UserCpCabinSpecialMemberCO;
import com.red.circle.other.app.dto.clientobject.user.user.UserCpCabinCO;
import com.red.circle.other.app.dto.clientobject.user.user.UserCpCabinSpecialCO;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.rds.entity.user.user.CpBlessRecord;
import com.red.circle.other.infra.database.rds.entity.user.user.CpCabinConfig;
import com.red.circle.other.infra.database.rds.entity.user.user.CpRelationship;
import com.red.circle.other.infra.database.rds.entity.user.user.CpValue;
import com.red.circle.other.infra.database.rds.service.user.user.CpBlessRecordService;
import com.red.circle.other.infra.database.rds.service.user.user.CpCabinAchieveService;
import com.red.circle.other.infra.database.rds.service.user.user.CpCabinConfigService;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.infra.database.rds.service.user.user.CpValueService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.num.NumUtils;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * CP(小屋、祝福)
 *
 * @author zongpubin on 2023/11/20
 */

@Component
@AllArgsConstructor
public class UserCpCabinQueryExe {

  private final CpValueService cpValueService;
  private final UserCpCabinConvertor userCpCabinConvertor;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final CpBlessRecordService cpBlessRecordService;
  private final CpCabinConfigService cpCabinConfigService;
  private final UserProfileGateway userProfileGateway;
  private final CpCabinAchieveService cpCabinAchieveService;
  private final CpRelationshipService cpRelationshipService;

  public UserCpCabinCO execute(UserIdCommonCmd cmd) {

    List<CpCabinConfig> cpCabinConfig = cpCabinConfigService.getCpCabinConfig(
        cmd.getReqSysOrigin().getOrigin());
    ResponseAssert.notEmpty(CommonErrorEnum.NOT_FOUND_MAPPING_INFO, cpCabinConfig);

    List<CpCabinConfigCO> cpCabinConfigList = userCpCabinConvertor.toCpCabinConfigCO(cpCabinConfig);
    CpRelationship relationship = cpRelationshipService.getByUserIdOrCpUserId(cmd.getUserId());
    Boolean selfCabin = Objects.equals(cmd.getUserId(), cmd.getReqUserId());

    if (Objects.isNull(relationship)) {
      UserCpCabinCO userCpCabinCO = new UserCpCabinCO();
      CpPairUserProfileCO cpPairUserProfileCO = new CpPairUserProfileCO();
      cpPairUserProfileCO.setMeUserProfile(userProfileAppConvertor.toUserProfileDTO(
          userProfileGateway.getByUserId(cmd.getReqUserId())));
      userCpCabinCO.setCpPairUserProfileCO(cpPairUserProfileCO);
      userCpCabinCO.setCpCabinConfigCO(cpCabinConfigList);
      userCpCabinCO.setCheckSelfCabin(selfCabin);
      userCpCabinCO.setCpValLastMonth(0L);
      return userCpCabinCO;
    }

    CpValue cpValue = cpValueService.getById(relationship.getCpValId());
    CpPairUserProfileCO cpPairUserProfileCO = new CpPairUserProfileCO();
    cpPairUserProfileCO.setCpUserProfile(userProfileAppConvertor.toUserProfileDTO(
        userProfileGateway.getByUserId(relationship.getCpUserId())));
    cpPairUserProfileCO.setMeUserProfile(userProfileAppConvertor.toUserProfileDTO(
        userProfileGateway.getByUserId(relationship.getUserId())));
    cpPairUserProfileCO.setDays(TimestampUtils.durationNowDays(relationship.getCreateTime()));

    Long lastMonthCpVal = cpCabinAchieveService.lastMonthCpVal(relationship.getCpValId());

    CpCabinConfigCO currentCpCabin = getCurrentCpCabinConfigCO(cpCabinConfigList, lastMonthCpVal);
    UserCpCabinSpecialCO specialCO = getUserCpCabinSpecialCO(relationship, cpPairUserProfileCO,
        currentCpCabin);

    return UserCpCabinCO.builder()
        .cpPairUserProfileCO(cpPairUserProfileCO)
        .cpCabinConfigCO(cpCabinConfigList)
        .blessVal(Optional.ofNullable(cpValue.getBlessVal()).map(BigDecimal::longValue).orElse(0L))
        .cpVal(NumUtils.formatBigDecimal(cpValue.getCpVal()))
        .cpValLastMonth(lastMonthCpVal)
        .historyCpValMax(cpCabinAchieveService.maxCpVal(relationship.getCpValId()))
        .currentCpCabinConfigCO(currentCpCabin)
        .checkSelfCabin(selfCabin)
        .userCpCabinSpecial(specialCO)
        .build();
  }

  private UserCpCabinSpecialCO getUserCpCabinSpecialCO(
      CpRelationship relationship, CpPairUserProfileCO cpPairUserProfileCO,
      CpCabinConfigCO currentCpCabin) {

    if (Objects.isNull(currentCpCabin)) {
      return null;
    }

    UserCpCabinSpecialCO specialCO = UserCpCabinSpecialCO.builder()
        .cpUsers(Lists.newArrayList(UserCpCabinSpecialMemberCO.builder()
                .userAvatar(cpPairUserProfileCO.getCpUserProfile().getUserAvatar())
                .userNickname(cpPairUserProfileCO.getCpUserProfile().getUserNickname())
                .build(),
            UserCpCabinSpecialMemberCO.builder()
                .userAvatar(cpPairUserProfileCO.getMeUserProfile().getUserAvatar())
                .userNickname(cpPairUserProfileCO.getMeUserProfile().getUserNickname())
                .build()))
        .resourceUrl(currentCpCabin.getSourceUrl())
        .build();
    List<CpBlessRecord> blessRecords = getBlessRecord(relationship);
    if (CollectionUtils.isEmpty(blessRecords)) {
      return specialCO;
    }

    Set<Long> sendUserIds = blessRecords.stream().map(CpBlessRecord::getSendUserId)
        .collect(Collectors.toSet());

    if (CollectionUtils.isNotEmpty(sendUserIds)) {
      Map<Long, UserProfile> userProfileMap = userProfileGateway.mapByUserIds(sendUserIds);
      specialCO.setMembers(blessRecords.stream().map(blessRecord -> {
        UserProfile userProfileCO = userProfileMap.get(blessRecord.getSendUserId());
        return UserCpCabinSpecialMemberCO.builder()
            .userAvatar(userProfileCO.getUserAvatar())
            .userNickname(userProfileCO.getUserNickname())
            .build();
      }).collect(Collectors.toList()));
    }

    return specialCO;
  }

  private List<CpBlessRecord> getBlessRecord(CpRelationship relationship) {
    return cpBlessRecordService.getBlessRecord(relationship.getUserId(),
        Sets.newHashSet(relationship.getCpUserId(), relationship.getUserId()));
  }

  private static CpCabinConfigCO getCurrentCpCabinConfigCO(List<CpCabinConfigCO> cpCabinConfigList,
      Long cpValLastMonth) {

    CpCabinConfigCO currentCpCabinConfigCO = null;

    for (CpCabinConfigCO cabinConfigCO : cpCabinConfigList) {
      if (cpValLastMonth >= Optional.ofNullable(cabinConfigCO.getCabinUnlockValue()).orElse(0L)) {
        currentCpCabinConfigCO = cabinConfigCO;
      }
    }
    return currentCpCabinConfigCO;
  }
}
