package com.red.circle.game.fruit.application.command;

import com.red.circle.game.fruit.application.convertor.GameFruitAppConvertor;
import com.red.circle.game.fruit.application.dto.clientobject.GameFruitAwardRecordCO;
import com.red.circle.game.fruit.application.dto.enums.ClaimStatusEnum;
import com.red.circle.game.fruit.core.domain.gateway.GameFruitUserBetGateway;
import com.red.circle.game.fruit.infrastructure.database.cache.service.GameFruitTaskCacheService;
import com.red.circle.game.fruit.infrastructure.database.entity.GameFruitAwardRecord;
import com.red.circle.game.fruit.infrastructure.database.entity.GameFruitLotteryRecord;
import com.red.circle.game.fruit.infrastructure.database.entity.GameFruitRoundRecord;
import com.red.circle.game.fruit.infrastructure.database.entity.GameFruitTaskAwardConfig;
import com.red.circle.game.fruit.infrastructure.database.entity.GameFruitUserBetRecord;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitAwardRecordService;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitDaysRecordService;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitLotteryRecordService;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitRoundRecordService;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitTaskAwardConfigService;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitUserDaysRankingService;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitUserService;
import com.red.circle.game.fruit.inner.enums.GameFruitTaskEnum;
import com.red.circle.game.fruit.props.GameProperties;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.ArithmeticUtils;
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.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 通知开奖
 *
 * @author lisizhe 2023/12/7  10:22
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class NoticeLotteryDrawExe {

  private final GameProperties gameProperties;
  private final WalletGoldClient walletGoldClient;
  private final UserProfileClient userProfileClient;
  private final GameFruitAppConvertor gameFruitAppConvertor;
  private final GameFruitUserService gameFruitUserService;
  private final GameFruitUserBetGateway gameFruitUserBetGateway;
  private final GameFruitTaskCacheService gameFruitTaskCacheService;
  private final GameFruitDaysRecordService gameFruitDaysRecordService;
  private final GameFruitAwardRecordService gameFruitAwardRecordService;
  private final GameFruitRoundRecordService gameFruitRoundRecordService;
  private final GameFruitLotteryRecordService gameFruitLotteryRecordService;
  private final GameFruitTaskAwardConfigService gameFruitTaskAwardConfigService;
  private final GameFruitUserDaysRankingService gameFruitUserDaysRankingService;

  public Boolean execute() {

    // 获取该轮记录
    GameFruitRoundRecord gameFruitRoundRecord = gameFruitRoundRecordService.getGameRound();

    if (Objects.isNull(gameFruitRoundRecord)) {
      return false;
    }

    //校验是否开奖
    if (CollectionUtils.isEmpty(
        gameFruitLotteryRecordService.getRoundLotteryPrize(gameFruitRoundRecord.getId()))) {
      return Boolean.FALSE;
    }

    String origin = gameProperties.getSysOrigin();

    // 重置时间
    /*gameFruitMemoryService.putRoundSec(
        GameTimelineManage.noticeLotteryDrawResultSecond);*/

    // 查询本轮中奖人员名单
    List<GameFruitAwardRecord> gameFruitAwardRecords = gameFruitAwardRecordService.listWaitingUser(
        gameFruitRoundRecord.getId(), ClaimStatusEnum.WAITING.name());

    // 校验是否已发放

    // 发放奖品
    sendAward(gameFruitAwardRecords, gameFruitRoundRecord.getId(), origin);
    return Boolean.TRUE;
  }


  /**
   * 发送奖励
   */
  private void sendAward(List<GameFruitAwardRecord> gameFruitAwardRecords, Long gameId,
      String origin) {
    Map<Long, List<GameFruitUserBetRecord>> mapGameFruitWinnerList = gameFruitUserBetGateway.gameFruitWinnerMapList(
        gameId, origin);

    Map<Long, List<GameFruitUserBetRecord>> mapGameFruitTransportList = gameFruitUserBetGateway.gameFruitTransportMapList(
        gameId, mapGameFruitWinnerList.keySet());

    Set<Long> userIds = mapGameFruitTransportList.keySet();
    //重置每日用户连赢轮数
    resetUserDayWinRounds(userIds);

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

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

    List<GameFruitAwardRecordCO> gameFruitAwardRecordCOS = gameFruitAwardRecords.stream()
        .map(item -> {
          // 获取每个用户的押注信息
          List<GameFruitUserBetRecord> gameFruitUserBetRecords = mapGameFruitWinnerList.get(
              item.getUserId());

          GameFruitAwardRecordCO gameFruitAwardRecordCO = gameFruitAppConvertor.toGameFruitAwardRecordCO(
              item);
          gameFruitAwardRecordCO.setWinningAmount(BigDecimal.ZERO);
          // 遍历用户押注信息，计算奖励金额
          gameFruitUserBetRecords.forEach(bet -> {
            gameFruitAwardRecordCO.setWinningAmount(gameFruitAwardRecordCO.getWinningAmount()
                .add(bet.getInvest().multiply(ArithmeticUtils.toBigDecimal(bet.getAward()))));
          });

          UserProfileDTO userProfile = userProfileMap.get(item.getUserId());

          if (Objects.isNull(userProfile)) {
            return gameFruitAwardRecordCO;
          }

          // 发送奖励
          walletGoldClient.changeBalance(GoldReceiptCmd.builder()
              .appIncome()
              .userId(item.getUserId())
              .eventId(item.getGameId())
              .sysOrigin(origin)
              .origin(GoldOrigin.GAME_FRUIT_AWARD)
              .amount(gameFruitAwardRecordCO.getWinningAmount())
              .remark("摩天轮游戏奖励：" + gameFruitAwardRecordCO.getWinningAmount())
              .build()).getBody().getBalance().getDollarAmount();

          // 记录某项中奖记录
          recordAward(gameId, item.getUserId());
          return gameFruitAwardRecordCO;
        }).toList();

    // 支出统计
    expendStats(gameId, gameFruitAwardRecordCOS, origin);
  }

  private void recordAward(Long gameId, Long userId) {

    Map<Long, List<GameFruitLotteryRecord>> gameFruitLotteryRecordMap = gameFruitLotteryRecordService.listLotteryHistoryByGameIds(
        Collections.singleton(gameId));

    List<GameFruitLotteryRecord> gameFruitLotteryRecords = gameFruitLotteryRecordMap.get(
        gameId);
    // 记录每天某项中奖次数
    if (gameFruitLotteryRecords.size() > 1) {
      // 蔬菜/披萨
      gameFruitTaskCacheService.recordGameFruitTaskAward(userId,
          GameFruitTaskEnum.WINNING_ONE_OF_THE_PRIZES_TWO.name());
    } else {
      // 单个奖品
      GameFruitLotteryRecord gameFruitLotteryRecord = gameFruitLotteryRecords.get(0);

      GameFruitTaskAwardConfig awardConfig = gameFruitTaskAwardConfigService.getByTaskType(
          GameFruitTaskEnum.WINNING_ONE_OF_THE_PRIZES_ONE.name());

      if (Objects.equals(awardConfig.getGameAwardId(),
          gameFruitLotteryRecord.getPrizeId().toString())) {
        gameFruitTaskCacheService.recordGameFruitTaskAward(userId,
            GameFruitTaskEnum.WINNING_ONE_OF_THE_PRIZES_ONE.name());
      }
    }

    // 记录每天游戏连赢轮数
    gameFruitTaskCacheService.addUserWinRounds(userId);
  }

  private void resetUserDayWinRounds(Set<Long> userIds) {
    GameFruitTaskAwardConfig awardConfig = gameFruitTaskAwardConfigService.getByTaskType(
        GameFruitTaskEnum.NUMBER_OF_WINNING_ROUNDS.name());
    for (Long userId : userIds) {
      Integer userWinRounds = gameFruitTaskCacheService.getUserWinRounds(userId);
      if (awardConfig.getQuantity() > Long.valueOf(userWinRounds)) {
        gameFruitTaskCacheService.resetUserWinRounds(userId);
      }
    }
  }

  /**
   * 支出统计
   */
  private void expendStats(Long gameId, List<GameFruitAwardRecordCO> gameFruitAwardRecords,
      String origin) {


    // 修改中奖名单领取状态
    gameFruitAwardRecordService.updateClaimStatus(gameId);

    // 累加用户每日盈利榜单
    gameFruitUserDaysRankingService.addDaysRankingEarning(gameFruitAwardRecords);

    // 计算平台总支出
    Integer expendSum = gameFruitAwardRecords.stream()
        .mapToInt(v -> v.getWinningAmount().intValue()).sum();

    // 累加中奖金额
    gameFruitUserService.plusProfit(gameFruitAwardRecords);

    // 累加每日平台总支出
    gameFruitDaysRecordService.addPlatformExpend(expendSum, origin);

    // 计算每轮游戏平台总支出
    gameFruitRoundRecordService.addPlatformExpend(gameId, expendSum);
  }
}
