package com.red.circle.other.app.inner.service.user.region.impl;

import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.other.app.inner.convertor.user.RegionConfigInnerConvertor;
import com.red.circle.other.app.inner.service.user.region.RegionConfigClientService;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.database.cache.service.user.SysRegionCacheService;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
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.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.enums.team.TeamMemberTargetStatus;
import com.red.circle.other.inner.model.cmd.user.SysRegionCmd;
import com.red.circle.other.inner.model.cmd.user.SysRegionConfigQryCmd;
import com.red.circle.other.inner.model.dto.user.reigon.RegionConfigDTO;
import com.red.circle.other.inner.model.dto.user.reigon.UserRegionDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.wallet.inner.endpoint.bank.UserBankCardClient;

import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * @author zongpubin on 2023/8/14
 */
@Service
@RequiredArgsConstructor
public class RegionConfigClientServiceImpl implements RegionConfigClientService {

  private final UserRegionGateway userRegionGateway;
  private final TeamMemberService teamMemberService;
  private final TeamProfileService teamProfileService;
  private final UserBankCardClient userBankCardClient;
  private final SysRegionCacheService regionCacheService;
  private final SysRegionConfigService sysRegionConfigService;
  private final TeamMemberTargetService teamMemberTargetService;
  private final RegionConfigInnerConvertor regionConfigInnerConvertor;

  @Override
  public RegionConfigDTO getRegionById(String id) {
    SysRegionConfig regionConfig = sysRegionConfigService.getById(id);
    return regionConfigInnerConvertor.toRegionConfigDTO(regionConfig);
  }

  @Override
  public RegionConfigDTO getRegionByUserId(Long userId) {
    return regionConfigInnerConvertor.toRegionConfigDTO(
        userRegionGateway.getRegionConfigByUserId(userId));
  }

  @Override
  public Map<String, String> getMetadata(String regionId) {
    return Optional.ofNullable(getRegionById(regionId))
        .map(RegionConfigDTO::getMetadata)
        .orElseGet(CollectionUtils::newHashMap);
  }

  @Override
  public Map<String, String> mapRegionNameBySysOrigin(String sysOrigin) {
    return sysRegionConfigService.mapRegionName(sysOrigin);
  }

  @Override
  public Map<String, String> mapRegionNameByRegionIds(Set<String> regionIds) {
    return sysRegionConfigService.mapRegionName(regionIds);
  }

  @Override
  public String getRegionName(String regionId) {
    return sysRegionConfigService.getRegionName(regionId);
  }

  @Override
  public void add(SysRegionCmd config) {

    config.setId(IdWorkerUtils.getIdStr());
    ResponseAssert.isFalse(UserErrorCode.CODE_ALREADY_EXISTS,
        sysRegionConfigService.existRegionCode(config.getRegionCode(), config.getId(), config.getSysOrigin()));
    SysRegionConfig regionConfig = regionConfigInnerConvertor.toSysRegionConfig(config);
    regionConfig.setWithdrawalWays(StringUtils.join(config.getWithdrawalWaysList(), ","));
    sysRegionConfigService.add(regionConfig);
    regionCacheService.remove(config.getSysOrigin());
  }

  @Override
  public void update(SysRegionCmd config) {

    ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
        StringUtils.isNotBlank(config.getId()));

    SysRegionConfig oldRegion = sysRegionConfigService.getById(config.getId());
    ResponseAssert.notNull(UserErrorCode.SYS_REGION_NOT_EXIST_ERROR, oldRegion);

    Map<String, String> newMetadata = Optional.ofNullable(config.getMetadata()).orElse(Map.of());
    Map<String, String> oldMetadata = Optional.ofNullable(oldRegion.getMetadata()).orElse(Map.of());

    if (Objects.equals(newMetadata.get("openDailyAutoSalary"), "true") &&
        !Objects.equals(oldMetadata.get("openDailyAutoSalary"), "true")) {

      // 将月结转换成日结则需要处理区域下所有代理的成员目标状态都修改成'AUTO'
      teamMemberTargetService.updateStatusByTeamIds(
          teamProfileService.listIdByRegion(
              config.getId()), TeamMemberTargetStatus.AUTO
      );

    }

    SysRegionConfig regionConfig = regionConfigInnerConvertor.toSysRegionConfig(config);
    regionConfig.setWithdrawalWays(StringUtils.join(config.getWithdrawalWaysList(), ","));
    sysRegionConfigService.update(regionConfig);
    regionCacheService.remove(config.getSysOrigin());

  }

  @Override
  public void resetWithdrawal(Long regionId) {

    List<TeamProfile> teamProfiles = teamProfileService.listRegionAll(Objects.toString(regionId));

    if (CollectionUtils.isEmpty(teamProfiles)) {
      return;
    }

    for (TeamProfile teamProfile : teamProfiles) {
      List<TeamMember> teamMembers = teamMemberService.listTeamMember(teamProfile.getId(),
          teamProfile.getSetting().getMaxMember());

      if (CollectionUtils.isEmpty(teamMembers)) {
        continue;
      }
      for (TeamMember teamMember : teamMembers) {
        userBankCardClient.removeMonthWithdrawal(teamMember.getMemberId());
      }
    }
  }

  @Override
  public List<RegionConfigDTO> listByCondition(SysRegionConfigQryCmd query) {
    return Optional.ofNullable(sysRegionConfigService.listByCondition(query))
        .map(configs -> configs.stream()
            .map(regionConfigInnerConvertor::toRegionConfigDTO)
            .collect(Collectors.toList()))
        .orElse(List.of());
  }

  @Override
  public Map<Long, String> mapRegionIdByUserIds(Set<Long> userIdSet) {
    List<UserRegionDTO> userRegions = userRegionGateway.mapRegionIdByUserIds(userIdSet);
    return userRegions.stream()
        .collect(Collectors.toMap(UserRegionDTO::getUserId, UserRegionDTO::getRegionId));
  }
}
