package com.bizzan.bitrade.service;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bizzan.bitrade.constant.TransactionType;
import com.bizzan.bitrade.dao.MemberHistoryDao;
import com.bizzan.bitrade.dao.MemberTransactionDao;
import com.bizzan.bitrade.dao.MemberWalletDao;
import com.bizzan.bitrade.dao.StakingWalletDao;
import com.bizzan.bitrade.entity.MemberWallet;
import com.bizzan.bitrade.entity.StakingWallet;
import com.bizzan.bitrade.entity.MemberHistory;
import com.bizzan.bitrade.service.Base.BaseService;
import com.bizzan.bitrade.util.DateUtil;
import com.bizzan.bitrade.util.RedisManager;
import com.bizzan.bitrade.vo.MemberTransactionStat;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class MemberHistoryService extends BaseService {

	@Autowired
    private MemberHistoryDao dao;
	
	@Autowired
    private MemberTransactionDao transactionDao;

	@Autowired
	private StakingWalletDao stakingWalletDao;

	@Autowired
	private MemberWalletDao memberWalletDao;

	@Autowired
	private RedisManager redisManager;

	public void startStat(Calendar now) {
		//Calendar now = Calendar.getInstance();
		java.text.SimpleDateFormat sdf1 = new java.text.SimpleDateFormat("yyyy-MM-dd");
    	String endTimeStr = sdf1.format(now.getTime());
    	now.add(Calendar.DATE, -1);
    	String startTimeStr = sdf1.format(now.getTime());
    	log.info("startTimeStr={}, endTimeStr={}", startTimeStr, endTimeStr);
		Object[][] stats = transactionDao.statByMemberIdAndType(startTimeStr, endTimeStr);
		
		if(stats.length == 0)
			return;
		
		MemberHistory memberHistory = new MemberHistory();
		//memberHistory.setStatistic_date(new Date());
		memberHistory.setMemberId(Long.parseLong(stats[0][0].toString()));
		for (Object[] stat : stats) {
			long memberId = Long.parseLong(stat[0].toString());
			if (memberId != memberHistory.getMemberId().longValue()) {
				snapshotStakingBalance(memberHistory);
				snapshotFundBalance(memberHistory);
				dao.save(memberHistory);
				memberHistory = new MemberHistory();
				//memberHistory.setStatistic_date(new Date());
				memberHistory.setMemberId(memberId);
			}
			
			BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(stat[3].toString()));
			TransactionType type = TransactionType.valueOfOrdinal(Integer.parseInt(stat[1].toString()));
			memberHistory.setBalance(memberHistory.getBalance().add(amount));
			switch (type) {
				case RECHARGE:
					memberHistory.setRecharge(memberHistory.getRecharge().add(amount));
					break;
				case WITHDRAW:
					memberHistory.setWithdraw(memberHistory.getWithdraw().add(amount));
					break;
				case TRANSFER_ACCOUNTS:
					if (amount.compareTo(BigDecimal.ZERO) > 0)
						memberHistory.setTransferIn(memberHistory.getTransferIn().add(amount));
					else
						memberHistory.setTransferOut(memberHistory.getTransferOut().add(amount));
					break;
				case ACTIVITY_AWARD:
					memberHistory.setActivityAward(memberHistory.getActivityAward().add(amount));
					break;
				case PROMOTION_AWARD:
					memberHistory.setPromotionAward(memberHistory.getPromotionAward().add(amount));
					break;
				case DIVIDEND:
					memberHistory.setDividend(memberHistory.getDividend().add(amount));
					break;
				case ADMIN_RECHARGE:
					memberHistory.setAdminRecharge(memberHistory.getAdminRecharge().add(amount));
					break;
				case CONTRACT_AWARD:
					memberHistory.setAward(memberHistory.getAward().add(amount));
					break;
				case CONTRACT_PROFIT:
					memberHistory.setProfit(memberHistory.getProfit().add(amount));
					break;
				case CONTRACT_LOSS:
					memberHistory.setLoss(memberHistory.getLoss().add(amount));
					break;
				case CONTRACT_FEE:
					memberHistory.setFee(memberHistory.getFee().add(amount));
					break;
				case CONTRACT_OVERNIGHT_FEE:
					if (amount.compareTo(BigDecimal.ZERO) > 0)
						memberHistory.setOvernightFeeIn(memberHistory.getOvernightFeeIn().add(amount));
					else
						memberHistory.setOvernightFeeOut(memberHistory.getOvernightFeeOut().add(amount));
					break;
				case FOLLOW_AWARD:
					memberHistory.setFollowAward(memberHistory.getFollowAward().add(amount));
					break;
				case FOLLOW_PROFIT:
					memberHistory.setFollowProfit(memberHistory.getFollowProfit().add(amount));
					break;
				case FOLLOW_LOSS:
					memberHistory.setFollowLoss(memberHistory.getFollowLoss().add(amount));
					break;
				case FOLLOW_FEE:
					memberHistory.setFollowFee(memberHistory.getFollowFee().add(amount));
					break;
				case FOLLOW_DIVIDEND:
					if (amount.compareTo(BigDecimal.ZERO) > 0)
						memberHistory.setFollowDividendIn(memberHistory.getFollowDividendIn().add(amount));
					else
						memberHistory.setFollowDividendOut(memberHistory.getFollowDividendOut().add(amount));
					break;
				case FOLLOW_OVERNIGHT_FEE:
					if (amount.compareTo(BigDecimal.ZERO) > 0)
						memberHistory.setFollowOvernightFeeIn(memberHistory.getFollowOvernightFeeIn().add(amount));
					else
						memberHistory.setFollowOvernightFeeOut(memberHistory.getFollowOvernightFeeOut().add(amount));
					break;
				case SPOT_AWARD:
					memberHistory.setExchangeAward(memberHistory.getExchangeAward().add(amount));
					break;
				case SPOT_PROFIT:
					memberHistory.setExchangeProfit(memberHistory.getExchangeProfit().add(amount));
					break;
				case SPOT_LOSS:
					memberHistory.setExchangeLoss(memberHistory.getExchangeLoss().add(amount));
					break;
				case SPOT_FEE:
					memberHistory.setExchangeFee(memberHistory.getExchangeFee().add(amount));
					break;
				case STAKING_IN:
					// 质押冻结：资金从可用余额转入质押余额，并非新增收益，抵消 balance 的错误累加
					memberHistory.setBalance(memberHistory.getBalance().subtract(amount));
					break;
				case STAKING_RELEASE:
					// 质押释放：资金从质押余额回归可用余额，已在 STAKING_IN 时扣除，抵消 balance 的重复累加
					memberHistory.setBalance(memberHistory.getBalance().subtract(amount));
					break;
				case STAKING_DEPOSIT:
					// 用户主动划入质押钱包：资金账户减少属内部划转，抵消 balance 的错误累加
					memberHistory.setBalance(memberHistory.getBalance().subtract(amount));
					break;
				case STAKING_WITHDRAW:
					// 用户主动从质押钱包划出：资金账户增加属内部划转，抵消 balance 的错误累加
					memberHistory.setBalance(memberHistory.getBalance().subtract(amount));
					break;
				case AIRDROP_REWARD:
					// 空投奖励：平台发放的真实新增收益，归入活动奖励统计
					memberHistory.setActivityAward(memberHistory.getActivityAward().add(amount));
					break;
				default:
					break;
			}
		}
		snapshotStakingBalance(memberHistory);
		snapshotFundBalance(memberHistory);
		dao.save(memberHistory);
	}

	/**
	 * 快照用户当前质押钱包折合 USDT 余额写入 memberHistory.stakingBalance
	 * <p>
	 * 遍历 staking_wallet，各币种 lockedBalance 通过 Redis 折合 USDT 累加
	 *
	 * @param memberHistory 当前统计记录
	 */
	private void snapshotStakingBalance(MemberHistory memberHistory) {
		BigDecimal total = BigDecimal.ZERO;

		// 遍历质押钱包各币种，锁定余额折合 USDT 累加
		List<StakingWallet> stakingWallets = stakingWalletDao.findAllByMemberId(memberHistory.getMemberId());
		for (StakingWallet w : stakingWallets) {
			BigDecimal amount = w.getLockedBalance();
			if (amount.compareTo(BigDecimal.ZERO) <= 0) {
				continue;
			}
			total = total.add(convertToUsdt(w.getCoinUnit(), amount));
		}

		memberHistory.setStakingBalance(total);
	}

	/**
	 * 快照用户当前资金钱包折合 USDT 余额写入 memberHistory.fundBalance
	 * <p>
	 * 遍历 member_wallet，USDT 直接计入，非 USDT 币种（balance + frozenBalance）通过 Redis 折合 USDT 累加
	 *
	 * @param memberHistory 当前统计记录
	 */
	private void snapshotFundBalance(MemberHistory memberHistory) {
		BigDecimal total = BigDecimal.ZERO;

		// 遍历资金钱包各币种，非 USDT 按价折算后累加
		List<MemberWallet> fundWallets = memberWalletDao.findAllByMemberId(memberHistory.getMemberId());
		for (MemberWallet w : fundWallets) {
			if (w.getCoin() == null) {
				continue;
			}
			String coinUnit = w.getCoin().getUnit();
			BigDecimal amount = w.getBalance().add(w.getFrozenBalance());
			if (amount.compareTo(BigDecimal.ZERO) <= 0) {
				continue;
			}
			total = total.add(convertToUsdt(coinUnit, amount));
		}

		memberHistory.setFundBalance(total);
	}

	/**
	 * 将指定币种数量折合为 USDT
	 * <p>
	 * USDT 直接返回原值；其他币种通过 Redis 读取价格，读不到返回 ZERO
	 *
	 * @param coinUnit 币种单位（如 "USDT"、"IBIT"）
	 * @param amount   币种数量
	 * @return 折合 USDT 金额，无法定价时返回 ZERO
	 */
	private BigDecimal convertToUsdt(String coinUnit, BigDecimal amount) {
		if ("USDT".equalsIgnoreCase(coinUnit)) {
			return amount;
		}
		BigDecimal price = redisManager.getSpotPriceUsdt(coinUnit);
		if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
			log.warn("[snapshotStakingBalance] 无法获取 {} 价格，跳过该币种统计", coinUnit);
			return BigDecimal.ZERO;
		}
		return amount.multiply(price);
	}

	public BigDecimal sumBalanceByMemberId(long memberId) {
		BigDecimal amount = dao.sumBalanceByMemberId(memberId);
		if(amount == null)
			return BigDecimal.ZERO;
		else
			return amount;
	}
	
	public BigDecimal sumFollowRevenueByMemberId(long memberId) {
		BigDecimal amount = dao.sumFollowRevenueByMemberId(memberId);
		if(amount == null)
			return BigDecimal.ZERO;
		else
			return amount;
	}
	
	public MemberHistory sumMemberHistoryByMemberId(long memberId) {
		return dao.sumMemberHistoryByMemberId(memberId);
	}

	/**
	 * 查询用户最新一条每日统计的质押余额快照（用于今日收益率基准分母）
	 *
	 * @param memberId 用户ID
	 * @return 最新质押余额快照，无记录返回 ZERO
	 */
	public BigDecimal getLatestStakingBalance(long memberId) {
		BigDecimal amount = dao.getLatestStakingBalance(memberId);
		if (amount == null) {
			return BigDecimal.ZERO;
		} else {
			return amount;
		}
	}
}
