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

import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.dto.cmd.activity.LotteryWithdrawCmd;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserProgress;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryWithdraw;
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserProgressService;
import com.red.circle.other.infra.database.rds.service.activity.LotteryWithdrawService;
import com.red.circle.other.infra.utils.ZonedDateTimeUtils;
import com.red.circle.other.inner.asserts.lottery.LotteryErrorCode;
import com.red.circle.tool.core.date.TimestampUtils;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Locale;
import java.util.concurrent.ThreadLocalRandom;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 提交抽奖提现申请.
 *
 * @author system
 * @since 2025-10-21
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class LotteryWithdrawApplyExe {

  private final LotteryUserProgressService lotteryUserProgressService;
  private final LotteryWithdrawService lotteryWithdrawService;

  @Transactional(rollbackFor = Exception.class)
  public void execute(LotteryWithdrawCmd cmd) {
    Long userId = cmd.requiredReqUserId();
    BigDecimal amount = cmd.getAmount();
    Long activityId = Long.valueOf(cmd.getActivityId());
    ResponseAssert.isTrue(LotteryErrorCode.INSUFFICIENT_WITHDRAWAL_REQ_AMOUNT,
        amount.compareTo(BigDecimal.valueOf(10)) >= 0);

    // 1. 获取用户本周累计金额
//    String weekKey = ZonedDateTimeUtils.getWeekKey();
    LotteryUserProgress progress = lotteryUserProgressService.query()
        .eq(LotteryUserProgress::getUserId, userId)
        .eq(LotteryUserProgress::getActivityId, activityId)
//        .eq(LotteryUserProgress::getWeekKey, weekKey)
        .getOne();

    ResponseAssert.notNull(LotteryErrorCode.NO_WITHDRAWAL_AMOUNT, progress);
    ResponseAssert.isTrue(LotteryErrorCode.NO_WITHDRAWAL_AMOUNT, 
        progress.getTotalAmount() != null && progress.getTotalAmount().compareTo(BigDecimal.ZERO) > 0);

    // 2. 计算可提现金额（总金额 - 已提现金额 - 待审核金额）
    BigDecimal withdrawnAmount = getWithdrawnAmount(userId, activityId);
    BigDecimal pendingAmount = getPendingAmount(userId, activityId);
    BigDecimal availableAmount = progress.getTotalAmount().subtract(withdrawnAmount).subtract(pendingAmount);

    // 3. 校验提现金额
    ResponseAssert.isTrue(LotteryErrorCode.INSUFFICIENT_WITHDRAWAL_AMOUNT, 
        amount.compareTo(availableAmount) <= 0);

    // 4. 创建提现申请
    LotteryWithdraw withdraw = new LotteryWithdraw();
    withdraw.setWithdrawNo(generateWithdrawNo());
    withdraw.setUserId(userId);
    withdraw.setActivityId(activityId);
    withdraw.setAmount(amount);
    withdraw.setContactNumber(cmd.getContactNumber());
    withdraw.setDescription(cmd.getDescription());
    withdraw.setCardImages(cmd.getCardImages());
    withdraw.setType("LOTTERY");
    withdraw.setStatus(0); // 待审核
    withdraw.setCreateTime(TimestampUtils.now());
    withdraw.setUpdateTime(TimestampUtils.now());

    lotteryWithdrawService.save(withdraw);

    log.info("Lottery withdraw application submitted, userId: {}, amount: {}, withdrawNo: {}", 
        userId, amount, withdraw.getWithdrawNo());
  }

  /**
   * 获取已提现金额.
   */
  private BigDecimal getWithdrawnAmount(Long userId, Long activityId) {
    return lotteryWithdrawService.query()
        .eq(LotteryWithdraw::getUserId, userId)
        .eq(LotteryWithdraw::getActivityId, activityId)
        .in(LotteryWithdraw::getStatus, 1, 3) // 已通过、已完成
        .list()
        .stream()
        .map(LotteryWithdraw::getAmount)
        .reduce(BigDecimal.ZERO, BigDecimal::add);
  }

  /**
   * 获取待审核金额.
   */
  private BigDecimal getPendingAmount(Long userId, Long activityId) {
    return lotteryWithdrawService.query()
        .eq(LotteryWithdraw::getUserId, userId)
        .eq(LotteryWithdraw::getActivityId, activityId)
        .eq(LotteryWithdraw::getStatus, 0) // 待审核
        .list()
        .stream()
        .map(LotteryWithdraw::getAmount)
        .reduce(BigDecimal.ZERO, BigDecimal::add);
  }

  /**
   * 生成提现单号.
   */
  private String generateWithdrawNo() {
    return "WD" + System.currentTimeMillis() + 
           String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
  }

}
