package com.red.circle.other.app.manager.activity.award;

import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.enums.SendPropsOrigin;
import com.red.circle.other.infra.common.activity.PropsActivitySendCommon;
import com.red.circle.other.infra.common.activity.send.SendRewardGroup;
import com.red.circle.other.infra.common.props.PropsSendCommon;
import com.red.circle.other.infra.database.mongo.entity.user.count.WeekCpValueCount;
import com.red.circle.other.infra.database.mongo.service.user.count.WeekCpValueCountService;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardConfig;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRuleConfig;
import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRewardConfigService;
import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRuleConfigService;
import com.red.circle.other.infra.utils.SeasonUtils;
import com.red.circle.other.inner.enums.activity.PropsActivityTypeEnum;
import com.red.circle.other.inner.model.cmd.material.PrizeDescribe;
import com.red.circle.other.inner.model.cmd.material.PrizeDescribeRewardCmd;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.DateFormatConstant;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.date.ZonedDateTimeUtils;
//import com.red.circle.wallet.client.gold.WalletGoldClient;
//import com.red.circle.wallet.inner.cmd.GoldReceiptCmd;
//import com.red.circle.wallet.inner.enums.GoldOrigin;
//import com.red.circle.wallet.inner.model.PennyAmount;
import com.red.circle.tool.core.tuple.PennyAmount;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * CP排行榜奖励发送管理器.
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CpRankingRewardManager {

  private final WeekCpValueCountService weekCpValueCountService;
  private final PropsActivityRuleConfigService propsActivityRuleConfigService;
  private final PropsActivitySendCommon sendPropsManager;
  private final WalletGoldClient walletGoldClient;
  private final StringRedisTemplate stringRedisTemplate;
  private final PropsActivityRewardConfigService propsActivityRewardConfigService;
  private final PropsSendCommon propsSendCommon;

  /**
   * 发送上周周榜前三名奖励
   */
  @Transactional(rollbackFor = Exception.class)
  public void sendLastWeekTopReward(SysOriginPlatformEnum sysOrigin) {
    String lastWeekDate = getLastWeekDate();
    log.info("[CP周榜] 开始发送上周周榜前三奖励, 系统平台: {}, 上周日期: {}", 
        sysOrigin.name(), lastWeekDate);

    try {
      // 1. 获取上周前三名
      List<WeekCpValueCount> lastWeekTop3 = weekCpValueCountService
          .listLastWeekTop(sysOrigin.name(), 3);

      if (CollectionUtils.isEmpty(lastWeekTop3)) {
        log.warn("[CP周榜] 上周前三不存在, 系统平台: {}", sysOrigin.name());
        return;
      }

      // 2. 获取周榜奖励配置
      List<PropsActivityRuleConfig> rewardConfigs = propsActivityRuleConfigService
          .listPlatformByActivityType(sysOrigin.getSysOrigin(), PropsActivityTypeEnum.WEEK_CP_GIFT);

      if (CollectionUtils.isEmpty(rewardConfigs) || rewardConfigs.size() < 3) {
        log.error("[CP周榜] 奖励配置不足3个, 系统平台: {}, 实际数量: {}", 
            sysOrigin.name(), rewardConfigs == null ? 0 : rewardConfigs.size());
        return;
      }

      // 3. 发放奖励
      for (int rank = 0; rank < Math.min(lastWeekTop3.size(), 3); rank++) {
        WeekCpValueCount cpCount = lastWeekTop3.get(rank);
        PropsActivityRuleConfig rewardConfig = rewardConfigs.get(rank);

        // 发送奖励
        sendWeekCpReward(sysOrigin, cpCount, rewardConfig, rank + 1, lastWeekDate);
      }

      log.info("[CP周榜] 上周周榜前三奖励发放完成, 系统平台: {}", sysOrigin.name());

    } catch (Exception e) {
      log.error("[CP周榜] 发送上周周榜奖励异常, 系统平台: {}", sysOrigin.name(), e);
      throw e;
    }
  }

  /**
   * 发送上赛季前三名奖励
   */
  @Transactional(rollbackFor = Exception.class)
  public void sendLastSeasonTopReward(SysOriginPlatformEnum sysOrigin) {
    String lastSeasonCycleKey = SeasonUtils.getLastSeasonCycleKey();
    log.info("[CP赛季榜] 开始发送上赛季前三奖励, 系统平台: {}, 上赛季: {}", 
        sysOrigin.name(), lastSeasonCycleKey);

    try {
      // 1. 获取上赛季前三名
      List<WeekCpValueCount> lastSeasonTop3 = weekCpValueCountService
          .listLastSeasonTop(sysOrigin.name(), 3);

      if (CollectionUtils.isEmpty(lastSeasonTop3)) {
        log.warn("[CP赛季榜] 上赛季前三不存在, 系统平台: {}", sysOrigin.name());
        return;
      }

      // 2. 获取赛季榜奖励配置
      List<PropsActivityRuleConfig> rewardConfigs = propsActivityRuleConfigService
          .listPlatformByActivityType(sysOrigin.getSysOrigin(), PropsActivityTypeEnum.SEASON_CP_GIFT);

      if (CollectionUtils.isEmpty(rewardConfigs) || rewardConfigs.size() < 3) {
        log.error("[CP赛季榜] 奖励配置不足3个, 系统平台: {}, 实际数量: {}", 
            sysOrigin.name(), rewardConfigs == null ? 0 : rewardConfigs.size());
        return;
      }

      // 3. 发放奖励
      for (int rank = 0; rank < Math.min(lastSeasonTop3.size(), 3); rank++) {
        WeekCpValueCount cpCount = lastSeasonTop3.get(rank);
        PropsActivityRuleConfig rewardConfig = rewardConfigs.get(rank);

        // 发送奖励
        sendSeasonCpReward(sysOrigin, cpCount, rewardConfig, rank + 1, lastSeasonCycleKey);
      }

      log.info("[CP赛季榜] 上赛季前三奖励发放完成, 系统平台: {}", sysOrigin.name());

    } catch (Exception e) {
      log.error("[CP赛季榜] 发送上赛季奖励异常, 系统平台: {}", sysOrigin.name(), e);
      throw e;
    }
  }

  /**
   * 发送周榜CP奖励
   */
  private void sendWeekCpReward(SysOriginPlatformEnum sysOrigin, 
                                WeekCpValueCount cpCount,
                                PropsActivityRuleConfig rewardConfig,
                                int rank, 
                                String weekDate) {
    ImmutablePair<Long, Long> userPair = weekCpValueCountService.parseUserIdPair(cpCount.getId());
    Long userOne = userPair.getLeft();
    Long userTwo = userPair.getRight();

    // 计算金币奖励
    double[] percentages = {0.04, 0.03, 0.02};
    double percentage = percentages[rank - 1];
    long goldReward = (long) (cpCount.getQuantity() * percentage);

    // 发送给用户1
    String eventIdOne = String.format("WK_CP_RW_%s_%d_%d", weekDate, userOne, rank);
    if (checkAndSetIdempotent(eventIdOne, 15)) {
      sendGoldAndProps(sysOrigin, userOne, goldReward, rewardConfig.getResourceGroupId(), 
          rewardConfig.getId(), SendPropsOrigin.WEEK_CP_GIFT, eventIdOne, 0);
      log.info("[CP周榜] 排名 {} 用户 {} 奖励发放成功, 金币: {}, 道具组: {}", 
          rank, userOne, goldReward, rewardConfig.getResourceGroupId());
    }

    // 发送给用户2
    String eventIdTwo = String.format("WK_CP_RW_%s_%d_%d", weekDate, userTwo, rank);
    if (checkAndSetIdempotent(eventIdTwo, 15)) {
      sendGoldAndProps(sysOrigin, userTwo, goldReward, rewardConfig.getResourceGroupId(), 
          rewardConfig.getId(), SendPropsOrigin.WEEK_CP_GIFT, eventIdTwo, 1);
      log.info("[CP周榜] 排名 {} 用户 {} 奖励发放成功, 金币: {}, 道具组: {}", 
          rank, userTwo, goldReward, rewardConfig.getResourceGroupId());
    }
  }

  /**
   * 发送赛季榜CP奖励
   */
  private void sendSeasonCpReward(SysOriginPlatformEnum sysOrigin, 
                                  WeekCpValueCount cpCount,
                                  PropsActivityRuleConfig rewardConfig,
                                  int rank, 
                                  String seasonCycleKey) {
    ImmutablePair<Long, Long> userPair = weekCpValueCountService.parseUserIdPair(cpCount.getId());
    Long userOne = userPair.getLeft();
    Long userTwo = userPair.getRight();

    // 赛季榜直接发送resourceGroupId奖励，不计算金币
    // 发送给用户1
    String eventIdOne = String.format("SN_CP_RW_%s_%d_%d", seasonCycleKey, userOne, rank);
    if (checkAndSetIdempotent(eventIdOne, 60)) {
      sendProps(sysOrigin, userOne, rewardConfig.getResourceGroupId(), 
          rewardConfig.getId(), SendPropsOrigin.SEASON_CP_GIFT);
      log.info("[CP赛季榜] 排名 {} 用户 {} 奖励发放成功, 道具组: {}", 
          rank, userOne, rewardConfig.getResourceGroupId());
    }

    // 发送给用户2
    String eventIdTwo = String.format("SN_CP_RW_%s_%d_%d", seasonCycleKey, userTwo, rank);
    if (checkAndSetIdempotent(eventIdTwo, 60)) {
      sendProps(sysOrigin, userTwo, rewardConfig.getResourceGroupId(), 
          rewardConfig.getId(), SendPropsOrigin.SEASON_CP_GIFT);
      log.info("[CP赛季榜] 排名 {} 用户 {} 奖励发放成功, 道具组: {}", 
          rank, userTwo, rewardConfig.getResourceGroupId());
    }
  }

  /**
   * 发送金币和道具
   */
  private void sendGoldAndProps(SysOriginPlatformEnum sysOrigin, 
                                Long userId, 
                                long goldAmount, 
                                Long resourceGroupId,
                                Long trackId,
                                SendPropsOrigin origin,
                                String eventId,
                                int sendIndex) {
    // 发送金币
    addUserGold(userId, sysOrigin.name(), goldAmount, eventId);

    SendRewardGroup param = SendRewardGroup.builder()
            .trackId(trackId)
            .sysOrigin(sysOrigin)
            .acceptUserId(userId)
            .resourceGroupId(resourceGroupId)
            .origin(origin)
            .build();
    // 发送道具
    List<PropsActivityRewardConfig> configs = propsActivityRewardConfigService.listByGroupId(
            param.getResourceGroupId());

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

    // 根据 sendIndex 筛选要发送的配置
    List<PropsActivityRewardConfig> filteredConfigs = filterConfigsBySendIndex(configs, sendIndex);

    if (CollectionUtils.isEmpty(filteredConfigs)) {
      log.warn("根据 sendIndex={} 筛选后没有可发送的配置, resourceGroupId={}", sendIndex, resourceGroupId);
      return;
    }

    propsSendCommon.send(new PrizeDescribeRewardCmd()
            .setTrackId(param.getTrackId())
            .setAcceptUserId(param.getAcceptUserId())
            .setOrigin(param.getOrigin())
            .setSysOrigin(param.getSysOrigin())
            .setPrizes(toListPrizeDescribe(filteredConfigs))
    );
  }

  /**
   * 根据 sendIndex 筛选配置
   * AVATAR_FRAME 类型根据 sendIndex 只保留第 sendIndex 个，其他类型正常返回
   * 例如: configs = [AVATAR_FRAME, AVATAR_FRAME, CHAT_BUBBLE]
   *       sendIndex = 0 -> 返回 [第一个 AVATAR_FRAME, CHAT_BUBBLE]
   *       sendIndex = 1 -> 返回 [第二个 AVATAR_FRAME, CHAT_BUBBLE]
   */
  private List<PropsActivityRewardConfig> filterConfigsBySendIndex(
          List<PropsActivityRewardConfig> configs, int sendIndex) {
    if (sendIndex < 0 || CollectionUtils.isEmpty(configs)) {
      return configs;
    }

    List<PropsActivityRewardConfig> result = Lists.newArrayList();
    String avatarFrameType = "AVATAR_FRAME";
    int avatarFrameCount = 0;

    for (PropsActivityRewardConfig config : configs) {
      if (Objects.equals(avatarFrameType, config.getDetailType())) {
        // AVATAR_FRAME 类型只保留第 sendIndex 个
        if (avatarFrameCount == sendIndex) {
          result.add(config);
        }
        avatarFrameCount++;
      } else {
        // 其他类型正常添加
        result.add(config);
      }
    }

    return result;
  }

  private List<PrizeDescribe> toListPrizeDescribe(List<PropsActivityRewardConfig> configs) {
    return configs.stream().map(this::toPrizeDescribe).collect(Collectors.toList());
  }

  private PrizeDescribe toPrizeDescribe(PropsActivityRewardConfig config) {
    return new PrizeDescribe()
            .setTrackId(config.getGroupId())
            .setType(config.getType())
            .setDetailType(config.getDetailType())
            .setContent(config.getContent())
            .setQuantity(config.getQuantity());
  }

  /**
   * 发送道具
   */
  private void sendProps(SysOriginPlatformEnum sysOrigin, 
                        Long userId, 
                        Long resourceGroupId,
                        Long trackId,
                         SendPropsOrigin origin) {
    sendPropsManager.sendActivityGroup(SendRewardGroup.builder()
        .trackId(trackId)
        .sysOrigin(sysOrigin)
        .acceptUserId(userId)
        .resourceGroupId(resourceGroupId)
        .origin(origin)
        .build());
  }

  /**
   * 增加用户金币
   */
  private void addUserGold(Long userId, String sysOrigin, Long amount, String eventId) {
    GoldReceiptCmd build = GoldReceiptCmd.builder()
        .appIncome()
        .userId(userId)
        .amount(PennyAmount.ofDollar(amount))
        .eventId(eventId)
        .sysOrigin(sysOrigin)
        .origin(GoldOrigin.CP_RANKING_REWARD)
        .build();

    try {
      walletGoldClient.changeBalance(build);
    } catch (Exception e) {
      log.error("增加金币失败 userId={} amount={} eventId={}", userId, amount, eventId, e);
      throw new RuntimeException("Failed to increase gold coins");
    }
  }

  /**
   * 幂等性检查
   */
  private boolean checkAndSetIdempotent(String eventId, int expireDays) {
    String key = "CP_REWARD_IDEMPOTENT:" + eventId;
    Boolean result = stringRedisTemplate.opsForValue()
        .setIfAbsent(key, "1", expireDays, TimeUnit.DAYS);
    
    if (Boolean.FALSE.equals(result)) {
      log.warn("奖励已发放, 跳过重复发送, eventId={}", eventId);
      return false;
    }
    return true;
  }

  /**
   * 获取上周一日期
   */
  private String getLastWeekDate() {
    return ZonedDateTimeUtils.format(
        ZonedDateTimeAsiaRiyadhUtils.getLastWeekMonday(),
        DateFormatConstant.yyyyMMdd
    );
  }
}
