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

import com.red.circle.common.business.enums.OperationUserOrigin;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.dto.cmd.team.TeamMemberRoleChangeCmd;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamApplicationProcess;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamApplicationProcessApproval;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.service.activity.ActivityAgentAnchorCountService;
import com.red.circle.other.infra.database.mongo.service.activity.AgentActivityCountService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamApplicationProcessApprovalService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamApplicationProcessService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberChangeRecordService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTargetService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService;
import com.red.circle.other.infra.database.rds.entity.team.TeamTerminationFeeRecord;
import com.red.circle.other.infra.database.rds.service.team.TeamTerminationFeeRecordService;
import com.red.circle.other.inner.model.dto.user.reigon.HostApplyQuitTeamCheckDTO;
import com.red.circle.other.inner.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.enums.team.TeamAppProcessApprovalReason;
import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus;
import com.red.circle.other.inner.enums.team.TeamApplicationType;
import com.red.circle.other.inner.enums.team.TeamMemberRole;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.dto.WalletReceiptResDTO;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 团队成员角色变更.
 *
 * @author pengliang on 2022/12/30
 */
@Component
@RequiredArgsConstructor
public class TeamMemberRoleChangeCmdExe {

  private final WalletGoldClient walletGoldClient;
  private final UserRegionGateway userRegionGateway;
  private final TeamMemberService teamMemberService;
  private final TeamProfileService teamProfileService;
  private final TeamMemberTargetService teamMemberTargetService;
  private final AgentActivityCountService agentActivityCountService;
  private final TeamApplicationProcessService teamApplicationProcessService;
  private final TeamMemberChangeRecordService teamMemberChangeRecordService;
  private final ActivityAgentAnchorCountService activityAgentAnchorCountService;
  private final TeamTerminationFeeRecordService teamTerminationFeeRecordService;
  private final TeamApplicationProcessApprovalService teamApplicationProcessApprovalService;

  public void execute(TeamMemberRoleChangeCmd cmd) {

    TeamMember teamMember = teamMemberService.getByMemberId(cmd.getReqUserId());
    ResponseAssert.notNull(TeamErrorCode.PERMISSION_DENIED, teamMember);
    ResponseAssert.isTrue(TeamErrorCode.PERMISSION_DENIED, Objects.equals(teamMember.getTeamId(),
        cmd.getTeamId()));
    ResponseAssert.isTrue(TeamErrorCode.PERMISSION_DENIED, !Objects.equals(teamMember.getRole(),
        TeamMemberRole.MEMBER));
    ResponseAssert.isFalse(TeamErrorCode.PERMISSION_DENIED, cmd.reqIsSelf(cmd.getChangeMemberId()));

    TeamMember changeMember = teamMemberService.getByMemberId(cmd.getChangeMemberId());
    ResponseAssert.notNull(TeamErrorCode.NOT_TEAM_MEMBER, changeMember);
    ResponseAssert.isTrue(TeamErrorCode.PERMISSION_DENIED, Objects.equals(changeMember.getTeamId(),
        cmd.getTeamId()));
    ResponseAssert.isFalse(TeamErrorCode.PERMISSION_DENIED, Objects.equals(changeMember.getRole(),
        TeamMemberRole.OWN));

    if (Objects.equals(changeMember.getRole().name(), cmd.getRole())) {
      return;
    }

    // 验证当前管理员数量,只能设置1个
    if (Objects.equals(cmd.getRole(), TeamMemberRole.ADMIN.name())) {
      ResponseAssert.isFalse(TeamErrorCode.ADMIN_LIMIT,
          teamMemberService.existsTeamAdmin(changeMember.getTeamId()));
    }

    if (Objects.equals(changeMember.getRole(), TeamMemberRole.ADMIN)
        || Objects.equals(cmd.getRole(), TeamMemberRole.ADMIN.name())) {
      ResponseAssert.isTrue(TeamErrorCode.PERMISSION_DENIED, Objects.equals(teamMember.getRole(),
          TeamMemberRole.OWN));
    }

    // 主动删除团队成员
    if (Objects.equals(cmd.getRole(), "TOURIST")) {

      HostApplyQuitTeamCheckDTO quitTeamCheck =
          userRegionGateway.getHostApplyQuitTeamCheckByRegionId(
              userRegionGateway.getRegionId(changeMember.getMemberId()));
      ResponseAssert.isTrue(TeamErrorCode.PERMISSION_DENIED,
          quitTeamCheck.getAllowQuit());

      // 活动业务
      activityBusiness(changeMember);

      // 将解约金80%拨款给代理
      sendTerminationFee(cmd);

      teamMemberService.removeMemberByMemberId(changeMember.getMemberId());

      if (Objects.equals(changeMember.getRole(), TeamMemberRole.ADMIN)) {
        teamProfileService.decrCounter(cmd.getTeamId());
      }

      if (Objects.equals(changeMember.getRole(), TeamMemberRole.MEMBER)) {
        teamProfileService.decrCounterMember(cmd.getTeamId());
      }

      // 移除目标
      teamMemberTargetService.removeUserTarget(ZonedDateTimeAsiaRiyadhUtils.nowYearMonthToInt(),
          changeMember.getMemberId());

      // 添加审批记录
      teamApplicationProcessApprovalService.add(new TeamApplicationProcessApproval()
          .setSysOrigin(cmd.requireReqSysOrigin())
          .setType(TeamApplicationType.TEAM)
          .setReason(getReason(teamMember))
          .setAssociateId(cmd.getTeamId())
          .setBeProcessUserId(cmd.getChangeMemberId())
          .setCreateTime(TimestampUtils.now())
          .setCreateUser(cmd.getReqUserId())
          .setCreateUserOrigin(OperationUserOrigin.APP.getValue())
      );

      // 标记已提交审核记录
      teamApplicationProcessService.changeUserTeamWaitReject(changeMember.getMemberId());

      // 添加主播变更记录
      teamMemberChangeRecordService.add(cmd.requireReqSysOrigin(), cmd.getChangeMemberId(), 1,
          teamProfileService.getTeamRegionId(cmd.getTeamId()), cmd.getReqUserId(),
          OperationUserOrigin.APP.getValue());

      return;
    }

    teamMemberService.updateMemberRole(cmd.getChangeMemberId(),
        TeamMemberRole.valueOf(cmd.getRole()),
        cmd.getReqUserId());

    if (Objects.equals(changeMember.getRole(), TeamMemberRole.ADMIN)
        && Objects.equals(cmd.getRole(), TeamMemberRole.MEMBER.name())) {
      teamProfileService.decrCounterAdmin(teamMember.getTeamId());
    }

    if (Objects.equals(changeMember.getRole(), TeamMemberRole.MEMBER)
        && Objects.equals(cmd.getRole(), TeamMemberRole.ADMIN.name())) {
      teamProfileService.incrCounterAdmin(teamMember.getTeamId());
    }

  }

  private void sendTerminationFee(TeamMemberRoleChangeCmd cmd) {

    TeamApplicationProcess process = teamApplicationProcessService.getQuitWaitApply(
        cmd.getChangeMemberId());

    if (Objects.isNull(process) || !Objects.equals(process.getStatus(),
        TeamApplicationProcessStatus.WAIT)) {
      return;
    }

    Long teamOwnUserId = teamProfileService.getOwnUserIdById(cmd.getTeamId());
    if (Objects.isNull(teamOwnUserId)) {
      return;
    }

    TeamTerminationFeeRecord terminationFeeRecord = getTerminationFeeRecord(process);
    if (Objects.isNull(terminationFeeRecord)) {
      return;
    }

    if (Objects.nonNull(terminationFeeRecord.getPayeeUserId())) {
      return;
    }
    BigDecimal amount = terminationFeeRecord.getTerminationFee().multiply(BigDecimal.valueOf(0.8))
        .setScale(0, RoundingMode.DOWN);

    WalletReceiptResDTO walletReceiptRes = ResponseAssert.requiredSuccess(
        walletGoldClient.changeBalance(
            GoldReceiptCmd.builder()
                .appIncome()
                .userId(teamOwnUserId)
                .sysOrigin(process.getSysOrigin())
                .eventId(Objects.toString(process.getId()))
                .amount(amount)
                .origin(GoldOrigin.HOST_TERMINATION_FEE)
                .originDescribe(GoldOrigin.HOST_TERMINATION_FEE.getDesc())
                .remark("")
                .closeDelayAsset()
                .opUserId(teamOwnUserId)
                .build()));

    if (Objects.isNull(walletReceiptRes)) {
      return;
    }

    terminationFeeRecord.setPayeeAmount(amount);
    terminationFeeRecord.setPayeeUserId(teamOwnUserId);
    terminationFeeRecord.setPayeeRunningWaterId(walletReceiptRes.getAssetRecordId());
    terminationFeeRecord.setUpdateTime(TimestampUtils.now());
    terminationFeeRecord.setUpdateUser(teamOwnUserId);
    teamTerminationFeeRecordService.updateSelectiveById(terminationFeeRecord);
  }

  private TeamTerminationFeeRecord getTerminationFeeRecord(TeamApplicationProcess process) {
    return teamTerminationFeeRecordService.getById(process.getId());
  }

  /**
   * 活动业务.
   */
  private void activityBusiness(TeamMember changeMember) {

    // 获得该成员目标值，然后减少活动数据中相应目标值（！务必放在【移除目标】前面）
    agentActivityCountService.reduceTarget(Set.of(changeMember.getTeamId()),
        teamMemberTargetService.getLatestInProgressTarget(changeMember.getMemberId()));

    // 归零活动积分
    activityAgentAnchorCountService
        .initZero(changeMember.getMemberId(), changeMember.getTeamId());
  }

  private TeamAppProcessApprovalReason getReason(TeamMember teamMember) {
    if (Objects.equals(teamMember.getRole(), TeamMemberRole.OWN)) {
      return TeamAppProcessApprovalReason.MEMBER_OWN_REMOVE;
    }

    if (Objects.equals(teamMember.getRole(), TeamMemberRole.ADMIN)) {
      return TeamAppProcessApprovalReason.MEMBER_ADMIN_REMOVE;
    }

    ResponseAssert.failure(TeamErrorCode.PERMISSION_DENIED);
    return null;
  }

}
