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

import com.google.common.collect.Lists;
import com.red.circle.common.business.enums.OperationUserOrigin;
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.team.TeamUserApplyRecordCO;
import com.red.circle.other.app.dto.cmd.team.TeamUserApplyRecordQryCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamApplicationProcess;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamApplicationProcessService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.inner.asserts.DynamicErrorCode;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus;
import com.red.circle.other.inner.enums.team.TeamMemberRole;
import com.red.circle.tool.core.collection.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 团队用户申请记录.
 *
 * @author pengshigang on 2022/12/20
 */
@Component
@RequiredArgsConstructor
public class TeamUserApplyRecordQryExe {

  private final TeamMemberService teamMemberService;
  private final UserProfileGateway userProfileGateway;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final TeamApplicationProcessService teamApplicationProcessService;

  public List<TeamUserApplyRecordCO> execute(TeamUserApplyRecordQryCmd cmd) {

    TeamApplicationProcessStatus status = TeamApplicationProcessStatus.valueOf(cmd.getStatus());
    ResponseAssert.notNull(TeamErrorCode.EXTRACTION_PARAMETER_ERROR, status);

    TeamMember teamMember = teamMemberService.getByMemberId(cmd.getReqUserId());
    ResponseAssert.notNull(TeamErrorCode.NOT_TEAM_MEMBER, teamMember);
    ResponseAssert.isTrue(DynamicErrorCode.NO_RELATED_INFORMATION_FOUND,
        Objects.equals(teamMember.getTeamId(), cmd.getTeamId()));

    ResponseAssert.isFalse(TeamErrorCode.PERMISSION_DENIED,
        Objects.equals(teamMember.getRole(), TeamMemberRole.MEMBER));

    List<TeamApplicationProcess> processList = teamApplicationProcessService.listTeamByTeamId(
        cmd.getTeamId(), status);
    if (CollectionUtils.isEmpty(processList)) {
      return Lists.newArrayList();
    }

    Set<Long> userIds = Stream.of(processList.stream().map(TeamApplicationProcess::getCreateUser)
                .filter(Objects::nonNull).collect(Collectors.toSet()),
            processList.stream().map(TeamApplicationProcess::getUpdateUser)
                .filter(Objects::nonNull).collect(Collectors.toSet()))
        .flatMap(Collection::stream).collect(Collectors.toSet());

    if (CollectionUtils.isEmpty(userIds)) {
      return Lists.newArrayList();
    }

    Map<Long, UserProfileDTO> userProfileMap = userProfileAppConvertor.toMapUserProfileDTO(
        userProfileGateway.mapByUserIds(userIds));
    if (CollectionUtils.isEmpty(userProfileMap)) {
      return Lists.newArrayList();
    }

    return processList.stream().map(process -> new TeamUserApplyRecordCO()
        .setId(process.getId())
        .setTeamId(process.getAssociateId())
        .setReason(process.getReason().name())
        .setStatus(process.getStatus().name())
        .setCreateTime(process.getCreateTime())
        .setUpdateTime(process.getUpdateTime())
        .setCreateUserProfile(
            Objects.equals(process.getCreateUserOrigin(), OperationUserOrigin.APP.getValue())
                ? userProfileMap.get(process.getCreateUser())
                : null)
        .setUpdateUserProfile(
            Objects.equals(process.getUpdateUserOrigin(), OperationUserOrigin.APP.getValue())
                ? userProfileMap.get(process.getUpdateUser())
                : null)
    ).filter(Objects::nonNull).toList();

  }

}
