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

import com.red.circle.component.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.dto.cmd.family.DisbandFamilyCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.common.family.FamilyNewsRecorder;
import com.red.circle.other.infra.database.cache.key.FamilyKeys;
import com.red.circle.other.infra.database.rds.entity.family.FamilyBaseInfo;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.service.family.FamilyBaseInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyLevelExpService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberTotalExpService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberWeekExpService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMonthExpService;
import com.red.circle.other.infra.database.rds.service.family.FamilyWeekExpService;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import com.red.circle.other.infra.enums.family.FamilyStatusEnum;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import com.red.circle.tool.core.collection.CollectionUtils;

import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 解散家族
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DisbandFamilyCmdExe {

  private final FamilyCommon familyCommon;
  private final FamilyNewsRecorder familyNewsRecorder;
  private final UserProfileGateway userProfileGateway;
  private final FamilyBaseInfoService familyBaseInfoService;
  private final FamilyMemberInfoService familyMemberInfoService;
  private final FamilyWeekExpService familyWeekExpService;
  private final FamilyMonthExpService familyMonthExpService;
  private final FamilyLevelExpService familyLevelExpService;
  private final FamilyMemberWeekExpService familyMemberWeekExpService;
  private final FamilyMemberTotalExpService familyMemberTotalExpService;
  private final RedisService redisService;

  @Transactional(rollbackFor = Exception.class)
  public void execute(DisbandFamilyCmd cmd) {

    FamilyMemberInfo memberInfo = familyMemberInfoService.getFamilyMemberByUserId(cmd.getReqUserId());
    ResponseAssert.notNull(FamilyErrorCode.NOT_EXIST_FAMILY_INFO_DATA, memberInfo);
    ResponseAssert.isTrue(FamilyErrorCode.ONLY_ADMIN_CAN_DISBAND_FAMILY, familyCommon.isAdmin(memberInfo.getMemberRole()));

    Long familyId = memberInfo.getFamilyId();
    FamilyBaseInfo familyBaseInfo = familyBaseInfoService.getBaseInfoById(familyId);
    ResponseAssert.notNull(FamilyErrorCode.NOT_EXIST_FAMILY_INFO_DATA, familyBaseInfo);
    List<FamilyMemberInfo> allMembers = familyMemberInfoService.listByFamilyId(familyId);
    clearFamilyData(familyId);
    
    disbandFamilyStatus(familyId);

    notifyAllMembers(allMembers, familyId);

    allMembers.forEach(member -> {
      redisService.setString(FamilyKeys.USER_LEAVE.getKey(member.getMemberUserId()), familyId, 1, TimeUnit.DAYS);
    });
  }

  private void clearFamilyData(Long familyId) {

    familyMemberInfoService.deleteByFamilyId(familyId);

    familyWeekExpService.deleteByFamilyId(familyId);
    familyMonthExpService.deleteByFamilyId(familyId);
    familyLevelExpService.deleteByFamilyId(familyId);

    familyMemberWeekExpService.deleteByFamilyId(familyId);
    familyMemberTotalExpService.deleteByFamilyId(familyId);
  }

  private void disbandFamilyStatus(Long familyId) {
    familyBaseInfoService.delFamily(familyId);
  }

  private void recordDisbandNews(String origin, Long familyId, String familyName) {
    familyNewsRecorder.recordAndUpdateNotice(
        origin,
        familyId,
        FamilyNewsTypeEnum.FAMILY_DISBANDED,
        null,
        familyName,
        null,
        null
    );
  }

  private void notifyAllMembers(List<FamilyMemberInfo> members, Long familyId) {
    if (CollectionUtils.isEmpty(members)) {
      return;
    }

    userProfileGateway.removeCacheAll(members.stream().map(FamilyMemberInfo::getMemberUserId).collect(Collectors.toSet()));
  }

}
