package com.red.circle.other.infra.common.team.decay;

import com.google.common.collect.Lists;
import com.red.circle.common.business.enums.OperationUserOrigin;
import com.red.circle.component.mq.MessageEvent;
import com.red.circle.component.mq.service.FixedTopic;
import com.red.circle.component.mq.service.SenderService;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.mq.business.model.event.BadgeOperateEvent;
import com.red.circle.mq.business.model.event.team.TeamSalaryCountEvent;
import com.red.circle.mq.rocket.business.producer.UserMqMessageService;
import com.red.circle.mq.rocket.business.streams.TeamSalaryCountSink;
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.TeamImportanceLog;
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.TeamBillCycleUtils;
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.TeamImportanceLogService;
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.BillDiamondBalanceDetailsService;
import com.red.circle.other.infra.database.rds.service.team.BillDiamondBalanceService;
import com.red.circle.other.infra.database.rds.service.team.TeamTerminationFeeRecordService;
import com.red.circle.other.inner.enums.material.BadgeKeyEnum;
import com.red.circle.other.inner.model.cmd.team.TeamMemberIdCmd;
import com.red.circle.other.inner.enums.team.TeamAppProcessApprovalReason;
import com.red.circle.other.inner.enums.team.TeamApplicationType;
import com.red.circle.other.inner.enums.team.TeamMemberRole;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
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.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 团队成员-移除.
 * <p>
 * TODO mark pl [腐烂的， 充满坏味道].
 *
 * @author pengliang on 2023/12/15
 */
@Component
@RequiredArgsConstructor
public class TeamMemberRemoveDecay {

  private final RedisService redisService;
  private final SenderService senderService;
  private final WalletGoldClient walletGoldClient;
  private final TeamMemberService teamMemberService;
  private final TeamProfileService teamProfileService;
  private final TeamMemberTargetService teamMemberTargetService;
  private final TeamImportanceLogService teamImportanceLogService;
  private final AgentActivityCountService agentActivityCountService;
  private final TeamMemberChangeRecordService teamMemberChangeRecordService;
  private final TeamApplicationProcessService teamApplicationProcessService;
  private final TeamTerminationFeeRecordService teamTerminationFeeRecordService;
  private final ActivityAgentAnchorCountService activityAgentAnchorCountService;
  private final TeamApplicationProcessApprovalService applicationProcessApprovalService;
  private final BillDiamondBalanceService billDiamondBalanceService;
  private final UserMqMessageService userMqMessageService;
  private final BillDiamondBalanceDetailsService billDiamondBalanceDetailsService;

  public void execute(TeamMemberIdCmd param) {

    // 并发操作可能造成， 数量累计不一致；降低概率使用for单个操作
    List<TeamApplicationProcessApproval> approvals = Lists.newArrayList();
    List<TeamImportanceLog> logList = Lists.newArrayList();

    param.getIds().forEach(memberSortId -> {

      TeamMember teamMember = processRemoveTeamMember(memberSortId);
      if (Objects.isNull(teamMember)) {
        return;
      }

      // 发送主播解约费
      sendTerminationFee(teamMember, param.getUpdateUser());

      // 活动业务
      activityBusiness(teamMember);

      approvals.add(
          new TeamApplicationProcessApproval()
              .setSysOrigin(teamMember.getSysOrigin())
              .setType(TeamApplicationType.TEAM)
              .setReason(TeamAppProcessApprovalReason.SYSTEM_MEMBER_REMOVE)
              .setAssociateId(teamMember.getTeamId())
              .setBeProcessUserId(teamMember.getMemberId())
              .setCreateTime(TimestampUtils.now())
              .setCreateUser(param.getUpdateUser())
              .setCreateUserOrigin(1)
      );
      logList.add(new TeamImportanceLog()
          .setRemarks("[后台]移除团队中的成员")
          .setSysOrigin(teamMember.getSysOrigin())
          .setAssociateId(teamMember.getTeamId())
          .setBeProcessUserId(teamMember.getMemberId())
          .setCreateUser(param.getUpdateUser())
          .setCreateUserOrigin(1)
      );

      teamMemberTargetService.removeUserTarget(TeamBillCycleUtils.getCalcBillBelong(),
          teamMember.getMemberId());

      teamMemberChangeRecordService.add(teamMember.getSysOrigin(), teamMember.getMemberId(), 1,
          teamProfileService.getTeamRegionId(teamMember.getTeamId()), param.getUpdateUser(),
          OperationUserOrigin.BACK.getValue());

      // 重新统计团队未出帐账单数据消息
      sendTeamSalaryCountMq(Set.of(teamMember.getTeamId()));

      // 移除用户账单钻石余额
      billDiamondBalanceService.removeByUserId(teamMember.getMemberId(), TeamBillCycleUtils.getCalcBillBelong());
      billDiamondBalanceDetailsService.removeByUserId(teamMember.getMemberId(), TeamBillCycleUtils.getCalcBillBelong());
    });

    if (CollectionUtils.isNotEmpty(approvals)) {
      applicationProcessApprovalService.addBatch(approvals);
    }
    if (CollectionUtils.isNotEmpty(logList)) {
      teamImportanceLogService.addBatch(logList);

      // 将申请加入或退出的审核中记录移除
      teamApplicationProcessService.deleteWaitByAppUserIds(
          logList.stream().map(TeamImportanceLog::getBeProcessUserId)
              .collect(Collectors.toSet()));
    }

  }

  /**
   * 重新统计团队未出帐账单数据消息.
   */
  private void sendTeamSalaryCountMq(Set<Long> teamIds) {

    senderService.sendEventMessage(MessageEvent.builder()
        .consumeId(IdWorkerUtils.getIdStr())
        .topic(FixedTopic.RC_DEFAULT_APP_ORDINARY)
        .tag(TeamSalaryCountSink.TAG)
        .body(new TeamSalaryCountEvent()
            .setTeamIds(teamIds)
            .setTimestamp(TimestampUtils.now())
        )
        .build());

  }

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

    // 减少代理积分
    agentActivityReduceTarget(teamMember);

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


  private void agentActivityReduceTarget(TeamMember teamMember) {
    agentActivityCountService.reduceTarget(Set.of(teamMember.getTeamId()),
        teamMemberTargetService.getLatestInProgressTarget(teamMember.getMemberId()));
  }

  private TeamMember processRemoveTeamMember(Long memberSortId) {
    String lockKey = "REMOVE_TEAM_MEMBER:" + memberSortId;
    if (!redisService.lock(lockKey, 60)) {
      return null;
    }
    TeamMember teamMember = teamMemberService.removeMember(memberSortId);
    if (Objects.isNull(teamMember)) {
      redisService.unlock(lockKey);
      return null;
    }

    if (TeamMemberRole.MEMBER.eq(teamMember.getRole())) {
      teamProfileService.decrCounterMember(teamMember.getTeamId());
    }
    if (TeamMemberRole.ADMIN.eq(teamMember.getRole())) {
      teamProfileService.decrCounter(teamMember.getTeamId());
    }


    userMqMessageService.sendBadgeOperateEvent(memberSortId, BadgeKeyEnum.AGENCY.name(), BadgeOperateEvent.OperationType.REMOVE.name());
    userMqMessageService.sendBadgeOperateEvent(memberSortId, BadgeKeyEnum.HOST.name(), BadgeOperateEvent.OperationType.REMOVE.name());

    redisService.unlock(lockKey);
    return teamMember;
  }


  private void sendTerminationFee(TeamMember teamMember, Long updateUser) {

    // 获得主播正在申请退出中的记录
    TeamApplicationProcess process = getQuitWaitApply(teamMember);
    if (Objects.isNull(process)) {
      return;
    }

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

    if (Objects.nonNull(terminationFeeRecord.getPayeeUserId())) {
      return;
    }

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

    BigDecimal amount = terminationFeeRecord.getTerminationFee().multiply(BigDecimal.valueOf(0.8))
        .setScale(0, RoundingMode.DOWN);

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

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

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

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

  private TeamApplicationProcess getQuitWaitApply(TeamMember teamMember) {
    return teamApplicationProcessService.getQuitWaitApply(teamMember.getMemberId());
  }
}
