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

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.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
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.service.MessageSenderService;
import com.red.circle.mq.rocket.business.streams.TeamSalaryCountSink;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.convertor.team.TeamInfraConvertor;
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.entity.team.team.TeamMemberTarget;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamProfile;
import com.red.circle.other.infra.database.mongo.entity.user.region.SysRegionConfig;
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.mongo.service.user.region.SysRegionConfigService;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.enums.material.BadgeConfigTypeEnum;
import com.red.circle.other.inner.enums.material.BadgeKeyEnum;
import com.red.circle.other.inner.model.cmd.team.MemberTeamChangeCmd;
import com.red.circle.other.inner.model.cmd.team.TeamMemberAddCmd;
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberDTO;
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.other.inner.enums.team.TeamMemberTargetIndex;
import com.red.circle.other.inner.enums.team.TeamMemberTargetStatus;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.DateFormatConstant;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * TODO mark pl [腐烂的， 充满坏味道].
 *
 * @author lisizhe 2023/11/6  11:02 修改成员归属团队
 */
@Component
@RequiredArgsConstructor
public class UpdateMemberTeamDecay {

  private final RedisService redisService;
  private final MessageSenderService senderService;
  private final TeamMemberService teamMemberService;
  private final UserMqMessageService userMqMessageService;
  private final TeamInfraConvertor teamInfraConvertor;
  private final TeamProfileService teamProfileService;
  private final TeamMemberAddDecay teamMemberAddDecay;
  private final UserProfileGateway userProfileGateway;
  private final SysRegionConfigService sysRegionConfigService;
  private final TeamMemberTargetService teamMemberTargetService;
  private final TeamImportanceLogService teamImportanceLogService;
  private final TeamMemberChangeRecordService teamMemberChangeRecordService;
  private final TeamApplicationProcessService teamApplicationProcessService;
  private final TeamApplicationProcessApprovalService applicationProcessApprovalService;

  public TeamMemberDTO execute(MemberTeamChangeCmd param) {

    TeamMember teamMember = teamMemberService.getByMemberId(param.getMemberUserId());
    ResponseAssert.notNull(TeamErrorCode.NOT_TEAM_MEMBER, teamMember);

    TeamProfile newTmpTeamProfile = teamProfileService.getAvailableByOwnUserId(param.getOwnUserId());
    ResponseAssert.notNull(TeamErrorCode.TEAM_NOT_FOUND, newTmpTeamProfile);

    ResponseAssert.isFalse(TeamErrorCode.USER_ALREADY_TEAM_MEMBER,
        Objects.equals(newTmpTeamProfile.getId(), teamMember.getTeamId()));

    ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT,
        Objects.equals(teamMember.getSysOrigin(), newTmpTeamProfile.getSysOrigin()));

    String lockKey = "UPDATE_MEMBER_TEAM:" + teamMember.getMemberId();
    ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT, redisService.lock(lockKey, 60));

    // 在删除之前先获得原团队
    TeamProfile teamProfile = teamProfileService.getById(teamMember.getTeamId());
    ResponseAssert.notNull(TeamErrorCode.USER_NOT_TEAM_MEMBER, teamProfile);

    // 移除成员
    TeamMember removeTeamMember = processRemoveTeamMember(teamMember.getSortId());
    if (Objects.isNull(removeTeamMember)) {
      redisService.unlock(lockKey);
      ResponseAssert.failure(CommonErrorCode.NOT_FOUND_RECORD_INFO);
      return null;
    }

    // 添加日志.
    applicationProcessApprovalService.add(
        new TeamApplicationProcessApproval()
            .setSysOrigin(teamMember.getSysOrigin())
            .setType(TeamApplicationType.TEAM)
            .setReason(TeamAppProcessApprovalReason.SWITCH_TEAM_REMOVE)
            .setAssociateId(teamMember.getTeamId())
            .setBeProcessUserId(teamMember.getMemberId())
            .setCreateTime(TimestampUtils.now())
            .setCreateUser(param.getUpdateUser())
            .setCreateUserOrigin(OperationUserOrigin.BACK.getValue())
    );

    teamImportanceLogService.add(new TeamImportanceLog()
        .setRemarks("[后台]修改团队成员归属团队")
        .setSysOrigin(teamMember.getSysOrigin())
        .setAssociateId(teamMember.getTeamId())
        .setBeProcessUserId(teamMember.getMemberId())
        .setCreateUser(param.getUpdateUser())
        .setCreateUserOrigin(1)
    );

    // 新团队 添加成员
    TeamProfile newTeamProfile = teamMemberAddDecay.execute(new TeamMemberAddCmd()
        .setOwnUserId(param.getOwnUserId())
        .setSysOrigin(param.getSysOrigin())
        .setTeamAccount(param.getTeamAccount())
        .setMemberUserId(param.getMemberUserId())
        .setRemarks(StringUtils.isNotBlank(param.getRemarks()) ? param.getRemarks()
            : removeTeamMember.getRemarks())
        .setCreateUser(param.getUpdateUser())
    );

    UserProfile userProfile = userProfileGateway.getByUserId(param.getMemberUserId());
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, newTeamProfile.getOwnUserId());

    // 移除历史申请
    teamApplicationProcessService.removeByUserId(param.getMemberUserId());

    // 如果是跨区域变更团队则需要将账单设置为历史状态，然后新建账单，否则正常变更.
    if (Objects.equals(newTeamProfile.getRegion(), teamProfile.getRegion())) {

      // 修改本月，目标归属
      teamMemberTargetService.updateThisMonthUserTargetAscription(removeTeamMember.getMemberId(),
          newTeamProfile.getId());

    } else {

      // 将之前的账单修改为历史存档状态
      teamMemberTargetService
          .updateThisMonthUserTargetHistoryStatusByUserId(param.getMemberUserId());

      Boolean isOpenAutoSalary = isOpenDailyAutoSalary(newTeamProfile.getRegion());

      // 检测账单是否已创建
      teamMemberTargetService.createIfAbsent(new TeamMemberTarget()
          .setTimeId(IdWorkerUtils.getId())
          .setSysOrigin(newTeamProfile.getSysOrigin())
          .setTeamId(newTeamProfile.getId())
          .setBillBelong(ZonedDateTimeAsiaRiyadhUtils.nowYearMonthToInt())
          .setBillTitle(ZonedDateTimeAsiaRiyadhUtils.nowFormat(DateFormatConstant.MM_SLASH_YYYY))
          .setUserId(param.getMemberUserId())
          .setRegion(newTeamProfile.getRegion())
          .setCountryCode(userProfile.getCountryCode())
          .setStatus(Boolean.TRUE.equals(isOpenAutoSalary) ? TeamMemberTargetStatus.AUTO
              : TeamMemberTargetStatus.NOT_RECORDED)
          .setDailyTargets(List.of(
              new TeamMemberTargetIndex()
                  .setOwnOnlineTime(0L)
                  .setOtherOnlineTime(0L)
                  .setAcceptGiftValue(0L)
                  .setGiveGiftValue(0L)
                  .setRoomValue(0L)
                  .setDateNumber(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt())
                  .setCreateTime(TimestampUtils.now())
                  .setUpdateTime(TimestampUtils.now())
          ))
          .setCreateTime(TimestampUtils.now())
          .setUpdateTime(TimestampUtils.now())
      );

      // 如两个区域不一致则添加变更记录
      teamMemberChangeRecordService.add(teamProfile.getSysOrigin(), param.getMemberUserId(), 1,
          teamProfile.getRegion(), param.getUpdateUser(), 1);

    }

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

    redisService.unlock(lockKey);

    return teamInfraConvertor.toTeamMemberDTO(
        teamMemberService.getByMemberId(param.getMemberUserId()));
  }


  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());
    }

    redisService.unlock(lockKey);

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


  /**
   * 重新统计团队未出帐账单数据消息.
   */
  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 Boolean isOpenDailyAutoSalary(String regionId) {

    SysRegionConfig region = sysRegionConfigService.getById(regionId);
    ResponseAssert.notNull(UserErrorCode.SYS_REGION_NOT_EXIST_ERROR, region);

    if (CollectionUtils.isEmpty(region.getMetadata())) {
      return Boolean.FALSE;
    }

    return Objects.equals(region.getMetadata().get("openDailyAutoSalary"), "true");
  }
}
