package com.red.circle.console.app.service.app.count.ops;

import com.google.common.collect.Maps;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.console.app.convertor.count.ops.CountCurrencyAppConvertor;
import com.red.circle.console.app.dto.clienobject.count.ops.CountDailyCurrencyCountGroupCO;
import com.red.circle.console.app.dto.clienobject.count.ops.CountDailyGoldOriginGroupCO;
import com.red.circle.console.app.dto.clienobject.count.ops.CountUserRechargeRankCO;
import com.red.circle.console.app.dto.clienobject.count.ops.CountUserRechargeRankGroupCO;
import com.red.circle.console.app.dto.clienobject.count.ops.CurrencyAnalyzeUserLogCO;
import com.red.circle.console.app.dto.clienobject.count.ops.CurrencyAnalyzeUserLogGroupCO;
import com.red.circle.console.app.dto.cmd.app.count.ops.GoldOriginProfileExportQry;
import com.red.circle.console.app.dto.cmd.app.count.ops.GoldOriginProfileQry;
import com.red.circle.console.infra.database.mongo.count.entity.CountGoldOriginDailyDetails;
import com.red.circle.console.infra.database.mongo.count.entity.CountUserDailyRechargeRank;
import com.red.circle.console.infra.database.mongo.count.entity.CurrencyAnalyzeUserLog;
import com.red.circle.console.infra.database.mongo.count.service.CountGoldOriginDailyDetailsService;
import com.red.circle.console.infra.database.mongo.count.service.CountUserDailyRechargeRankService;
import com.red.circle.console.infra.database.mongo.count.service.CurrencyAnalyzeUserLogService;
import com.red.circle.console.infra.database.rds.entity.count.StatisticsDailyCurrencyCountPlatform;
import com.red.circle.console.infra.database.rds.service.count.StatisticsDailyCurrencyCountPlatformService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.dto.WalletGoldCountDTO;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * 货币统计.
 *
 * @author pengliang on 2024/1/22
 */
@Service
@RequiredArgsConstructor
public class CountCurrencyServiceImpl implements CountCurrencyService {

  private final WalletGoldClient walletGoldClient;
  private final UserProfileClient userProfileClient;
  private final CountCurrencyAppConvertor countCurrencyAppConvertor;
  private final CurrencyAnalyzeUserLogService currencyAnalyzeUserLogService;
  private final CountUserDailyRechargeRankService countUserDailyRechargeRankService;
  private final CountGoldOriginDailyDetailsService countGoldOriginDailyDetailsService;
  private final StatisticsDailyCurrencyCountPlatformService countDailyCurrencyCountPlatformService;

  @Override
  public List<CountDailyCurrencyCountGroupCO> listLast30Days() {
    var platformLatest30Day = countDailyCurrencyCountPlatformService.mapSysOriginLatestGroup(
        30);
    if (CollectionUtils.isEmpty(platformLatest30Day)) {
      return CollectionUtils.newArrayList();
    }
    return platformLatest30Day.keySet().stream()
        .sorted(Comparator.comparing(SysOriginPlatformEnum::getSort))
        .map(key -> {
          List<StatisticsDailyCurrencyCountPlatform> currencyCountPlatforms = platformLatest30Day
              .get(key);
          return new CountDailyCurrencyCountGroupCO()
              .setSysOrigin(key)
              .setSysOriginName(SysOriginPlatformEnum.getSysOriginName(key))
              .setLastMonths(countCurrencyAppConvertor.toListCountDailyCurrencyCountPlatformCO(
                  currencyCountPlatforms));
        }).toList();
  }

  @Override
  public List<CountDailyGoldOriginGroupCO> listLastGoldOrigin30Days(String origin) {
    return toCountDailyGoldOriginGroupDTO(
        countGoldOriginDailyDetailsService.listLatestDays(origin, 30));
  }

  @Override
  public List<WalletGoldCountDTO> listGoldOriginProfile(GoldOriginProfileQry query) {
    return walletGoldClient.listWalletGoldCount(query.getSysOrigin(), query.getDateNumber())
        .getBody();
  }

  @Override
  public List<WalletGoldCountDTO> listGoldOriginProfileExport(GoldOriginProfileExportQry query) {
    return walletGoldClient.listWalletGoldCountExport(query.getSysOrigin(), query.getMonthNumber())
        .getBody();
  }

  @Override
  public List<CurrencyAnalyzeUserLogGroupCO> listDailyUserGoldTop(Integer dateNumber) {
    List<CurrencyAnalyzeUserLog> userLogs = currencyAnalyzeUserLogService.list(dateNumber);

    if (CollectionUtils.isEmpty(userLogs)) {
      return CollectionUtils.newArrayList();
    }

    Map<Long, UserProfileDTO> userProfileMap = userProfileClient.mapByUserIds(
        userLogs.stream().map(CurrencyAnalyzeUserLog::getUserId).collect(
            Collectors.toSet())
    ).getBody();

    List<CurrencyAnalyzeUserLogCO> userVoLogs = userLogs.stream().map(log -> {
      CurrencyAnalyzeUserLogCO co = countCurrencyAppConvertor.toCurrencyAnalyzeUserLogCO(log);
      co.setUserProfile(userProfileMap.get(log.getUserId()));
      return co;
    }).toList();

    Map<String, List<CurrencyAnalyzeUserLogCO>> detailMap = userVoLogs.stream()
        .collect(Collectors.groupingBy(CurrencyAnalyzeUserLogCO::getSysOrigin));

    return detailMap.keySet().stream()
        .sorted(Comparator.comparing(SysOriginPlatformEnum::getSort))
        .map(key -> {
          List<CurrencyAnalyzeUserLogCO> values = detailMap.get(key);
          return new CurrencyAnalyzeUserLogGroupCO()
              .setSysOrigin(key)
              .setSysOriginName(SysOriginPlatformEnum.getSysOriginName(key))
              .setItems(values);
        }).toList();
  }

  @Override
  public List<CountUserRechargeRankGroupCO> listDailyUserRechargeTop(Integer dateNumber) {

    List<CountUserDailyRechargeRank> ranks = countUserDailyRechargeRankService.list(dateNumber);

    if (CollectionUtils.isEmpty(ranks)) {
      return CollectionUtils.newArrayList();
    }

    Map<Long, UserProfileDTO> userProfileMap = userProfileClient.mapByUserIds(
        ranks.stream().map(CountUserDailyRechargeRank::getUserId).collect(
            Collectors.toSet())
    ).getBody();

    List<CountUserRechargeRankCO> userVoLogs = ranks.stream().map(log -> {
      CountUserRechargeRankCO co = countCurrencyAppConvertor.toCountUserRechargeRankCO(log);
      co.setUserProfile(userProfileMap.get(log.getUserId()));
      return co;
    }).toList();

    Map<String, List<CountUserRechargeRankCO>> detailMap = userVoLogs.stream()
        .collect(Collectors.groupingBy(CountUserRechargeRankCO::getSysOrigin));

    return detailMap.keySet().stream()
        .sorted(Comparator.comparing(SysOriginPlatformEnum::getSort))
        .map(key -> new CountUserRechargeRankGroupCO()
            .setSysOrigin(key)
            .setSysOriginName(SysOriginPlatformEnum.getSysOriginName(key))
            .setItems(detailMap.get(key))
        ).toList();
  }

  @Override
  public void countIntegral(Integer countTimeNumber, LocalDate countTime, LocalDate endCountTime) {
    countDailyCurrencyCountPlatformService.countIntegral(countTimeNumber, countTime, endCountTime);
  }

  private List<CountDailyGoldOriginGroupCO> toCountDailyGoldOriginGroupDTO(
      List<CountGoldOriginDailyDetails> list) {
    Map<String, List<CountGoldOriginDailyDetails>> detailMap = Optional.ofNullable(list)
        .map(counts -> counts.stream()
            .collect(Collectors.groupingBy(CountGoldOriginDailyDetails::getSysOrigin)))
        .orElseGet(Maps::newHashMap);

    return detailMap.keySet().stream()
        .sorted(Comparator.comparing(SysOriginPlatformEnum::getSort))
        .map(key -> new CountDailyGoldOriginGroupCO()
            .setSysOrigin(key)
            .setSysOriginName(SysOriginPlatformEnum.getSysOriginName(key))
            .setList(
                countCurrencyAppConvertor.toListDailyGoldOriginDetailsCO(detailMap.get(key))))
        .collect(Collectors.toList());
  }

}
