package com.red.circle.other.app.command.family;

import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.family.FamilyMemberCO;
import com.red.circle.other.app.dto.clientobject.family.FamilyMemberListCO;
import com.red.circle.other.app.dto.cmd.family.FamilyMemberListQueryCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.rds.dto.family.FamilyMemberExpDTO;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberWeekExpService;
import com.red.circle.other.infra.enums.family.FamilyRoleEnum;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import com.red.circle.other.inner.enums.team.TeamMemberRole;
import com.red.circle.other.inner.model.dto.famliy.FamilyDetailsDTO;
import com.red.circle.other.inner.model.dto.user.OwnSpecialIdDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.NumUtils;

import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 家族成员.
 * </p>
 *
 * @author pengshigang
 * @since 2021-07-23
 */
@Component
@RequiredArgsConstructor
public class FamilyMemberListExe {

  private final FamilyCommon familyCommon;
  private final UserProfileGateway userProfileGateway;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final FamilyMemberWeekExpService familyMemberWeekExpService;
  private final TeamMemberService teamMemberService;

  public FamilyMemberListCO execute(FamilyMemberListQueryCmd cmd) {

    FamilyDetailsDTO familyDetails = familyCommon.getFamilyDetails(cmd.getReqSysOrigin().getOrigin(), cmd.getFamilyId());

    ResponseAssert.isTrue(FamilyErrorCode.NOT_EXIST_FAMILY_INFO_DATA,
        familyCommon.isExistFamilyById(cmd.getFamilyId()));


    if (cmd.getAccount() != null && !cmd.getAccount().isEmpty()) {
      UserProfile accountNew = userProfileGateway.getByAccountNew(cmd.getReqSysOrigin().getOrigin(), cmd.getAccount());
      cmd.setMemberUserId(Optional.ofNullable(accountNew).map(UserProfile::getId).orElse(-1L));
    }

    List<FamilyMemberExpDTO> members = pageList(cmd);
    if (CollectionUtils.isEmpty(members)) {
      return new FamilyMemberListCO()
          .setFamilyId(cmd.getFamilyId())
          .setMaxMember(familyDetails.getMaxMember())
          .setMaxManager(familyDetails.getMaxManager())
          .setMembers(CollectionUtils.newArrayList());
    }

    Map<Long, UserProfileDTO> mapUserBase = mapUserProfile(members);
    if (CollectionUtils.isEmpty(mapUserBase)) {
      return new FamilyMemberListCO()
          .setFamilyId(cmd.getFamilyId())
          .setMaxMember(familyDetails.getMaxMember())
          .setMaxManager(familyDetails.getMaxManager())
          .setMembers(CollectionUtils.newArrayList());
    }

    Map<Long, TeamMember> teamMemberMap = mapTeamMember(members);

    List<FamilyMemberCO> memberCOList = getMemberCO(members, mapUserBase, teamMemberMap);

    return new FamilyMemberListCO()
        .setFamilyId(cmd.getFamilyId())
        .setMaxMember(familyDetails.getMaxMember())
        .setMaxManager(familyDetails.getMaxManager())
        .setMembers(memberCOList);
  }

  private List<FamilyMemberCO> getMemberCO(List<FamilyMemberExpDTO> members,
                                           Map<Long, UserProfileDTO> userProfileMap,
                                           Map<Long, TeamMember> teamMemberMap) {

    return members.stream().map(member -> {
      UserProfileDTO user = userProfileMap.get(member.getMemberUserId());
      TeamMember teamMember = teamMemberMap.get(member.getMemberUserId());
      return new FamilyMemberCO()
          .setFamilyId(member.getFamilyId())
          .setMemberId(member.getId())
          .setMemberUserId(member.getMemberUserId())
          .setMemberAvatar(user.getUserAvatar())
          .setAccount(user.getAccount())
          .setSpecialAccount(Optional.ofNullable(user.getOwnSpecialId()).map(OwnSpecialIdDTO::getAccount).orElse(null))
          .setMemberNickname(user.getUserNickname())
          .setMemberRole(member.getMemberRole())
          .setAgent(Objects.nonNull(teamMember) && TeamMemberRole.OWN.eq(teamMember.getRole()))
          .setAnchor(Objects.nonNull(teamMember))
          ;

    }).filter(Objects::nonNull).toList();
  }

  private Map<Long, UserProfileDTO> mapUserProfile(List<FamilyMemberExpDTO> members) {
    return userProfileAppConvertor.toMapUserProfileDTO(userProfileGateway.mapByUserIds(
        members.stream().map(FamilyMemberExpDTO::getMemberUserId).collect(Collectors.toSet())));
  }

  private Map<Long, TeamMember> mapTeamMember(List<FamilyMemberExpDTO> members) {
    Set<Long> collect = members.stream().map(FamilyMemberExpDTO::getMemberUserId).collect(Collectors.toSet());
    List<TeamMember> teamMemberList = teamMemberService.listByMemberIds(collect);
    return teamMemberList.stream().collect(Collectors.toMap(TeamMember::getMemberId, e -> e, (v1, v2) -> v1));
  }

  private List<FamilyMemberExpDTO> pageList(FamilyMemberListQueryCmd cmd) {
    return familyMemberWeekExpService
        .pageByFamilyId(cmd.getFamilyId(),
            List.of(FamilyRoleEnum.MANAGE, FamilyRoleEnum.MEMBER, FamilyRoleEnum.ADMIN), cmd.getPageNo(),
            cmd.getPageSize(), cmd.getMemberUserId());
  }


}
