package com.bizzan.bitrade.service;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.bizzan.bitrade.constant.BooleanEnum;
import com.bizzan.bitrade.constant.NotifyType;
import com.bizzan.bitrade.constant.PageModel;
import com.bizzan.bitrade.constant.TransactionType;
import com.bizzan.bitrade.dao.CoinDao;
import com.bizzan.bitrade.dao.MemberDao;
import com.bizzan.bitrade.dao.MemberDepositDao;
import com.bizzan.bitrade.dao.MemberWalletDao;
import com.bizzan.bitrade.dao.StakingWalletDao;
import com.bizzan.bitrade.entity.StakingWallet;
import com.bizzan.bitrade.dto.MemberWalletDTO;
import com.bizzan.bitrade.entity.Coin;
import com.bizzan.bitrade.entity.Member;
import com.bizzan.bitrade.entity.MemberDeposit;
import com.bizzan.bitrade.entity.MemberTransaction;
import com.bizzan.bitrade.entity.MemberWallet;
import com.bizzan.bitrade.entity.Order;
import com.bizzan.bitrade.entity.OtcCoin;
import com.bizzan.bitrade.entity.QMember;
import com.bizzan.bitrade.entity.QMemberWallet;
import com.bizzan.bitrade.es.ESUtils;
import com.bizzan.bitrade.exception.InformationExpiredException;
import com.bizzan.bitrade.service.Base.BaseService;
import com.bizzan.bitrade.service.ExperienceGiftRecordService;
import com.bizzan.bitrade.util.BigDecimalUtils;
import com.bizzan.bitrade.util.MessageResult;
import com.bizzan.bitrade.vendor.provider.SMSProvider;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;

import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;

@Service
@Slf4j
public class MemberWalletService extends BaseService {

	@Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    private SMSProvider smsProvider;
	@Autowired
    private MemberService memberService;
	@Autowired
    private MemberDao memberDao;
    @Autowired
    private MemberWalletDao memberWalletDao;
    @Autowired
    private StakingWalletDao stakingWalletDao;
    @Autowired
    private CoinDao coinDao;
    @Autowired
    private MemberTransactionService transactionService;
    @Autowired
    private MemberDepositDao depositDao;
    @Autowired(required=false)
    private ESUtils esUtils;

    @Autowired(required=false)
    private ExperienceGiftRecordService experienceGiftRecordService;
    
    public MemberWallet save(MemberWallet wallet) {
        return memberWalletDao.saveAndFlush(wallet);
    }

    /**
     * 获取钱包
     *
     * @param coin     otc币种
     * @param memberId
     * @return
     */
    public MemberWallet findByOtcCoinAndMemberId(OtcCoin coin, long memberId) {
        Coin coin1 = coinDao.findByUnit(coin.getUnit());
        return memberWalletDao.findByCoinAndMemberId(coin1, memberId);
    }

    /**
     * 钱包充值
     *
     * @param wallet
     * @param amount
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public MessageResult recharge(MemberWallet wallet, BigDecimal amount) {
        if (wallet == null) {
            return new MessageResult(500, "wallet cannot be null");
        }
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return new MessageResult(500, "amount must large then 0");
        }
        int result = memberWalletDao.increaseBalance(wallet.getId(), amount);
        if (result > 0) {
            MemberTransaction transaction = new MemberTransaction();
            transaction.setAmount(amount);
            transaction.setSymbol(wallet.getCoin().getUnit());
            transaction.setAddress(wallet.getAddress());
            transaction.setMemberId(wallet.getMemberId());
            transaction.setType(TransactionType.RECHARGE);
            transaction.setFee(BigDecimal.ZERO);
            transaction.setDiscountFee("0");
            transactionService.save(transaction);
            //增加记录
            return new MessageResult(0, "success");
        } else {
            return new MessageResult(500, "recharge failed");
        }
    }

    /**
     * 钱包充值
     *
     * @param coin    币种名称
     * @param address 地址
     * @param amount  金额
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public MessageResult recharge(Coin coin, String address, BigDecimal amount, String txid) {
        MemberWallet wallet = findByCoinAndAddress(coin, address);
        if (wallet == null) {
            return new MessageResult(500, "wallet cannot be null");
        }
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return new MessageResult(500, "amount must large then 0");
        }
        MemberDeposit deposit = new MemberDeposit();
        deposit.setAddress(address);
        deposit.setAmount(amount);
        deposit.setMemberId(wallet.getMemberId());
        deposit.setTxid(txid);
        deposit.setUnit(wallet.getCoin().getUnit());
        depositDao.save(deposit);

        // ERC20 USDT充值，余额增加到USDT上
        if(coin.getUnit().equals("EUSDT")||coin.getUnit().equals("TUSDT")||coin.getUnit().equals("USDT-BEP20")) {
            MemberWallet walletShadow = findByCoinUnitAndMemberId("USDT", wallet.getMemberId());
            memberWalletDao.increaseBalance(walletShadow.getId(), amount);
        } else {
            memberWalletDao.increaseBalance(wallet.getId(), amount);
        }
        
        MemberTransaction transaction = new MemberTransaction();
        transaction.setAmount(amount);
        transaction.setSymbol(wallet.getCoin().getNameCn());
        transaction.setAddress(wallet.getAddress());
        transaction.setMemberId(wallet.getMemberId());
        transaction.setType(TransactionType.RECHARGE);
        transaction.setFee(BigDecimal.ZERO);
        transaction.setDiscountFee("0");
        transaction.setRealFee("0");
        transaction.setCreateTime(new Date());

        transaction = transactionService.save(transaction);
        
        kafkaTemplate.send("trading-account-change", wallet.getMemberId()+"");
        
        JSONObject rechargeActivity = new JSONObject();
    	rechargeActivity.put("memberId", wallet.getMemberId());
    	Member member = memberService.findOne(wallet.getMemberId());
    	rechargeActivity.put("inviterId", member.getInviterId());
    	rechargeActivity.put("amount", amount);
    	//kafkaTemplate.send("recharge-activity", rechargeActivity.toJSONString());
    	kafkaTemplate.send("after-deposit", rechargeActivity.toJSONString());

    	// 异步发放注册体验金（@Async，不阻塞充值流程）
    	if (experienceGiftRecordService != null) {
    	    experienceGiftRecordService.grantRegisterTrigger(wallet.getMemberId(), amount, member.getRegistrationTime(), member.getRegistrationIp());
    	}

        net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();
        jsonObject.put("amount", amount);
        jsonObject.put("unit", wallet.getCoin().getUnit());
        log.info("jsonObject={}", jsonObject);
        memberService.notifyByEmail(wallet.getMemberId(), NotifyType.RECHARGE, jsonObject);
        log.info("jsonObject1={}", jsonObject);
        if(member != null ) {
        	try {
				smsProvider.sendCustomMessage(member.getMobilePhone(), "尊敬的用户：恭喜您充值"+ wallet.getCoin().getUnit() + "成功，充值数量为：" + amount.stripTrailingZeros().toPlainString());
			} catch (Exception e) {
				e.printStackTrace();
			}
        }
        return new MessageResult(0, "success");
    }
    
    /**
     * 钱包充值(EOS地址类型）
     *
     * @param coin    币种名称
     * @param address 地址
     * @param amount  金额
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public MessageResult recharge2(Long userId, Coin coin, String address, BigDecimal amount, String txid) {
        MemberWallet wallet = findByCoinAndMemberId(coin, userId);
        if (wallet == null) {
            return new MessageResult(500, "wallet cannot be null");
        }
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return new MessageResult(500, "amount must large then 0");
        }
        MemberDeposit deposit = new MemberDeposit();
        deposit.setAddress(address);
        deposit.setAmount(amount);
        deposit.setMemberId(wallet.getMemberId());
        deposit.setTxid(txid);
        deposit.setUnit(wallet.getCoin().getUnit());
        depositDao.save(deposit);

        wallet.setBalance(wallet.getBalance().add(amount));
        MemberTransaction transaction = new MemberTransaction();
        transaction.setAmount(amount);
        transaction.setSymbol(wallet.getCoin().getUnit());
        transaction.setAddress(address);
        transaction.setMemberId(wallet.getMemberId());
        transaction.setType(TransactionType.RECHARGE);
        transaction.setFee(BigDecimal.ZERO);
        transaction.setDiscountFee("0");
        transaction.setRealFee("0");
        transaction.setCreateTime(new Date());

        transaction = transactionService.save(transaction);

        Member mRes = memberDao.findOne(wallet.getMemberId());
        if(mRes != null ) {
        	try {
				smsProvider.sendCustomMessage(mRes.getMobilePhone(), "尊敬的用户：恭喜您充值"+ wallet.getCoin().getUnit() + "成功，充值数量为：" + amount.stripTrailingZeros().toPlainString());
			} catch (Exception e) {
				e.printStackTrace();
			}
        }
        return new MessageResult(0, "success");
    }

    /**
     * 按会员ID充值（适用于平台归集地址模式，无法通过地址反查用户钱包的场景）
     * 逻辑与 recharge(Coin, String, BigDecimal, String) 一致，但通过 memberId 定位钱包
     *
     * @param memberId        会员ID，来自 coin_recharge_order.member_id
     * @param coin            充值币种实体
     * @param rechargeAddress 平台归集地址（记录到 member_deposit，便于对账）
     * @param amount          链上确认到账金额
     * @param txid            链上交易 hash
     * @return 操作结果
     * @author auto
     * @date 2026-05-13
     */
    @Transactional(rollbackFor = Exception.class)
    public MessageResult rechargeByMemberId(Long memberId, Coin coin, String rechargeAddress,
                                            BigDecimal amount, String txid) {
        // 1. 通过 memberId + coin 查找用户钱包
        MemberWallet wallet = findByCoinAndMemberId(coin, memberId);
        if (wallet == null) {
            return new MessageResult(500, "wallet cannot be null");
        }
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return new MessageResult(500, "amount must large then 0");
        }

        // 2. 记录 member_deposit 充值流水（归集地址作为 address 便于链上对账）
        MemberDeposit deposit = buildMemberDeposit(memberId, coin, rechargeAddress, amount, txid);
        depositDao.save(deposit);

        // 3. 增加余额：有上级币种则入账上级钱包，否则入账自身
        String parentCoinName = coin.getParentCoinName();
        MemberWallet targetWallet = wallet;
        if (parentCoinName != null && !parentCoinName.isEmpty()) {
            MemberWallet parentWallet = findByCoinUnitAndMemberId(parentCoinName, memberId);
            if (parentWallet != null) {
                targetWallet = parentWallet;
            }
        }
        memberWalletDao.increaseBalance(targetWallet.getId(), amount);

        // 4. 记录 member_transaction 流水
        MemberTransaction transaction = buildRechargeTransaction(wallet, amount, rechargeAddress);
        transactionService.save(transaction);

        // 5. 发送 Kafka 通知
        kafkaTemplate.send("trading-account-change", memberId + "");

        Member member = memberService.findOne(memberId);

        // 6. 发送邮件 + 短信通知
        net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();
        jsonObject.put("amount", amount);
        jsonObject.put("unit", wallet.getCoin().getUnit());
        memberService.notifyByEmail(memberId, NotifyType.RECHARGE, jsonObject);
        if (member != null) {
            try {
                smsProvider.sendCustomMessage(member.getMobilePhone(),
                        "尊敬的用户：恭喜您充值" + wallet.getCoin().getUnit()
                                + "成功，充值数量为：" + amount.stripTrailingZeros().toPlainString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return new MessageResult(0, "success");
    }

    /**
     * 构建 member_deposit 充值记录
     */
    private MemberDeposit buildMemberDeposit(Long memberId, Coin coin, String address,
                                              BigDecimal amount, String txid) {
        MemberDeposit deposit = new MemberDeposit();
        deposit.setMemberId(memberId);
        deposit.setUnit(coin.getUnit());
        deposit.setAddress(address);
        deposit.setAmount(amount);
        deposit.setTxid(txid);
        return deposit;
    }

    /**
     * 构建充值流水记录
     */
    private MemberTransaction buildRechargeTransaction(MemberWallet wallet, BigDecimal amount,
                                                        String address) {
        MemberTransaction transaction = new MemberTransaction();
        transaction.setAmount(amount);
        transaction.setSymbol(wallet.getCoin().getNameCn());
        transaction.setAddress(address);
        transaction.setMemberId(wallet.getMemberId());
        transaction.setType(TransactionType.RECHARGE);
        transaction.setFee(BigDecimal.ZERO);
        transaction.setDiscountFee("0");
        transaction.setRealFee("0");
        transaction.setCreateTime(new Date());
        return transaction;
    }


    /**
     * 根据币种和钱包地址获取钱包
     *
     * @param coin
     * @param address
     * @return
     */
    public MemberWallet findByCoinAndAddress(Coin coin, String address) {
        return memberWalletDao.findByCoinAndAddress(coin, address);
    }
    
    public MemberWallet findByAddress(String address) {
        return memberWalletDao.findByAddress(address);
    }

    /**
     * 根据币种和用户ID获取钱包
     *
     * @param coin
     * @param member
     * @return
     */
    public MemberWallet findByCoinAndMember(Coin coin, Member member) {
        return memberWalletDao.findByCoinAndMemberId(coin, member.getId());
    }

    public MemberWallet findByCoinUnitAndMemberId(String coinUnit, Long memberId) {
        Coin coin = coinDao.findByUnit(coinUnit);
        return memberWalletDao.findByCoinAndMemberId(coin, memberId);
    }

    public MemberWallet findByCoinAndMemberId(Coin coin, Long memberId) {
        return memberWalletDao.findByCoinAndMemberId(coin, memberId);
    }
    
    public MemberWallet findByMemberId(Long memberId) {
        return this.findByCoinUnitAndMemberId("USDT", memberId);
    }
    
    public List<MemberWallet> findRechargeByMemberId(Long memberId) {
        return memberWalletDao.findRechargeByMemberId(memberId);
    }

    /**
     * 根据用户查找所有钱包
     *
     * @param member
     * @return
     */
    public List<MemberWallet> findAllByMemberId(Member member) {
        return memberWalletDao.findAllByMemberId(member.getId());
    }

    public List<MemberWallet> findAllByMemberId(Long memberId) {
        return memberWalletDao.findAllByMemberId(memberId);
    }
    
    public BigDecimal getTotalBalanceByIds(List<Long> ids) {
    	BigDecimal balance = memberWalletDao.getTotalBalanceByIds(ids);
    	if(balance == null)
    		return BigDecimal.ZERO;
    	return balance;
    }
    
    public BigDecimal sumBalance() {
    	BigDecimal balance = memberWalletDao.sumBalance();
    	if(balance == null)
    		return BigDecimal.ZERO;
    	return balance;
    }
    
    public BigDecimal sumBalanceByMemberId(Long memberId) {
    	BigDecimal balance = memberWalletDao.sumBalanceByMemberId(memberId);
    	if(balance == null)
    		return BigDecimal.ZERO;
    	return balance;
    }
    
    public BigDecimal sumBalanceByMemberIds(List<Long> ids) {
    	BigDecimal balance = memberWalletDao.sumBalanceByMemberIds(ids);
    	if(balance == null)
    		return BigDecimal.ZERO;
    	return balance;
    }

    /**
     * 冻结钱包
     *
     * @param memberWallet
     * @param amount
     * @return
     */
    public MessageResult freezeBalance(MemberWallet memberWallet, BigDecimal amount) {
        int ret = memberWalletDao.freezeBalance(memberWallet.getId(), amount);
        if (ret > 0) {
            return MessageResult.success();
        } else {
            return MessageResult.error("Information Expired");
        }
    }
    
    public int freezeBalance(Long walletId, BigDecimal amount) {
        return memberWalletDao.freezeBalance(walletId, amount);
        
    }

    /**
     * 解冻钱包
     *
     * @param memberWallet
     * @param amount
     * @return
     */
    public MessageResult thawBalance(MemberWallet memberWallet, BigDecimal amount) {
        int ret = memberWalletDao.thawBalance(memberWallet.getId(), amount);
        if (ret > 0) {
            return MessageResult.success();
        } else {
            log.info("====order cancel=====订单取消异常（amount）："+amount);
            return MessageResult.error("Information Expired");
        }
    }

    /**
     * 放行更改双方钱包余额
     *
     * @param order
     * @param ret
     * @throws InformationExpiredException
     */
    public void transfer(Order order, int ret) throws InformationExpiredException {
        if (ret == 1) {
            MemberWallet customerWallet = findByOtcCoinAndMemberId(order.getCoin(), order.getCustomerId());
            int is = memberWalletDao.decreaseFrozen(customerWallet.getId(), order.getNumber());
            if (is > 0) {
                MemberWallet memberWallet = findByOtcCoinAndMemberId(order.getCoin(), order.getMemberId());
                int a = memberWalletDao.increaseBalance(memberWallet.getId(), BigDecimalUtils.sub(order.getNumber(), order.getCommission()));
                if (a <= 0) {
                    throw new InformationExpiredException("Information Expired");
                }
            } else {
                throw new InformationExpiredException("Information Expired");
            }
        } else {
            MemberWallet customerWallet = findByOtcCoinAndMemberId(order.getCoin(), order.getMemberId());
            int is = memberWalletDao.decreaseFrozen(customerWallet.getId(), BigDecimalUtils.add(order.getNumber(), order.getCommission()));
            if (is > 0) {
                MemberWallet memberWallet = findByOtcCoinAndMemberId(order.getCoin(), order.getCustomerId());
                int a = memberWalletDao.increaseBalance(memberWallet.getId(), order.getNumber());
                if (a <= 0) {
                    throw new InformationExpiredException("Information Expired");
                }
            } else {
                throw new InformationExpiredException("Information Expired");
            }
        }

    }



    /* */

    /**
     * 放行更改双方钱包余额
     *
     * @param order
     * @param ret
     * @throws InformationExpiredException
     */
    public void transferAdmin(Order order, int ret) throws InformationExpiredException {
        if (ret == 1 || ret == 4) {
            trancerDetail(order, order.getCustomerId(), order.getMemberId());
        } else {
            trancerDetail(order, order.getMemberId(), order.getCustomerId());

        }

    }


    private void trancerDetail(Order order, long sellerId, long buyerId) throws InformationExpiredException {
        MemberWallet customerWallet = findByOtcCoinAndMemberId(order.getCoin(), sellerId);
        //卖币者，买币者要处理的金额
        BigDecimal sellerAmount, buyerAmount;
        if (order.getMemberId() == sellerId) {
            sellerAmount = BigDecimalUtils.add(order.getNumber(), order.getCommission());
            buyerAmount = order.getNumber();
        } else {
            sellerAmount = order.getNumber();
            buyerAmount = order.getNumber().subtract(order.getCommission());
        }
        int is = memberWalletDao.decreaseFrozen(customerWallet.getId(), sellerAmount);
        if (is > 0) {
            MemberWallet memberWallet = findByOtcCoinAndMemberId(order.getCoin(), buyerId);
            int a = memberWalletDao.increaseBalance(memberWallet.getId(), buyerAmount);
            if (a <= 0) {
                throw new InformationExpiredException("Information Expired");
            }
        } else {
            throw new InformationExpiredException("Information Expired");
        }
    }

    public int deductBalance(MemberWallet memberWallet, BigDecimal amount) {
        return memberWalletDao.decreaseBalance(memberWallet.getId(), amount);
    }
    
    public int decreaseBalance(Long id, BigDecimal amount) {
        return memberWalletDao.decreaseBalance(id, amount);
    }

    @Override
    public List<MemberWallet> findAll() {
        return memberWalletDao.findAll();
    }

    public List<MemberWallet> findAllByCoin(Coin coin) {
        return memberWalletDao.findAllByCoin(coin);
    }

    /**
     * 锁定钱包
     *
     * @param uid
     * @param unit
     * @return
     */
    @Transactional
    public boolean lockWallet(Long uid, String unit) {
        MemberWallet wallet = findByCoinUnitAndMemberId(unit, uid);
        if (wallet != null && wallet.getIsLock() == BooleanEnum.IS_FALSE) {
            wallet.setIsLock(BooleanEnum.IS_TRUE);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 解锁钱包
     *
     * @param uid
     * @param unit
     * @return
     */
    @Transactional
    public boolean unlockWallet(Long uid, String unit) {
        MemberWallet wallet = findByCoinUnitAndMemberId(unit, uid);
        if (wallet != null && wallet.getIsLock() == BooleanEnum.IS_TRUE) {
            wallet.setIsLock(BooleanEnum.IS_FALSE);
            return true;
        } else {
            return false;
        }
    }

    public MemberWallet findOneByCoinNameAndMemberId(String coinName, long memberId) {
        BooleanExpression and = QMemberWallet.memberWallet.coin.name.eq(coinName)
                .and(QMemberWallet.memberWallet.memberId.eq(memberId));
        return memberWalletDao.findOne(and);
    }

    public Page<MemberWalletDTO> joinFind(List<Predicate> predicates,QMember qMember ,QMemberWallet qMemberWallet,PageModel pageModel) {
        List<OrderSpecifier> orderSpecifiers = pageModel.getOrderSpecifiers();
        predicates.add(qMember.id.eq(qMemberWallet.memberId));
        JPAQuery<MemberWalletDTO> query = queryFactory.select(
                        Projections.fields(MemberWalletDTO.class, qMemberWallet.id.as("id"),qMemberWallet.memberId.as("memberId") ,qMember.username,qMember.realName.as("realName"),
                        qMember.email,qMember.mobilePhone.as("mobilePhone"),qMemberWallet.balance,qMemberWallet.address,qMemberWallet.coin.unit
                        ,qMemberWallet.frozenBalance.as("frozenBalance"),qMemberWallet.balance.add(qMemberWallet.frozenBalance).as("allBalance"))).from(QMember.member,QMemberWallet.memberWallet).where(predicates.toArray(new Predicate[predicates.size()]))
                        .orderBy(qMemberWallet.balance.desc())
                        .orderBy(orderSpecifiers.toArray(new OrderSpecifier[orderSpecifiers.size()]));

        List<MemberWalletDTO> content = query.offset((pageModel.getPageNo()-1)*pageModel.getPageSize()).limit(pageModel.getPageSize()).fetch();
        long total = query.fetchCount();
        return new PageImpl<>(content, pageModel.getPageable(), total);
    }

    public Page<MemberWalletDTO> joinFind(List<Predicate> predicates,QMember qMember ,QMemberWallet qMemberWallet,PageModel pageModel,String allBalance) {
        List<OrderSpecifier> orderSpecifiers = pageModel.getOrderSpecifiers();
        predicates.add(qMember.id.eq(qMemberWallet.memberId));
        JPAQuery<MemberWalletDTO> query = queryFactory.select(
                Projections.fields(MemberWalletDTO.class, qMemberWallet.id.as("id"),qMemberWallet.memberId.as("memberId") ,qMember.username,qMember.realName.as("realName"),
                        qMember.email,qMember.mobilePhone.as("mobilePhone"),qMemberWallet.balance,qMemberWallet.address,qMemberWallet.coin.unit
                        ,qMemberWallet.frozenBalance.as("frozenBalance"),
                        qMemberWallet.balance.add(qMemberWallet.frozenBalance).as("allBalance")))
                .from(QMember.member,QMemberWallet.memberWallet).
                        where(predicates.toArray(new Predicate[predicates.size()]));
                if(allBalance != null){
                    // 判断加好了   重新打包部署一下就行   我俩出去一下
                    query.orderBy(qMemberWallet.balance.desc());
                }
                query.orderBy(orderSpecifiers.toArray(new OrderSpecifier[orderSpecifiers.size()]));

        List<MemberWalletDTO> content = query.offset((pageModel.getPageNo()-1)*pageModel.getPageSize()).limit(pageModel.getPageSize()).fetch();
        long total = query.fetchCount();
        return new PageImpl<>(content, pageModel.getPageable(), total);
    }

    public BigDecimal getAllBalance(String coinName){
        return memberWalletDao.getWalletAllBalance(coinName);
    }

    public MemberDeposit findDeposit(String address,String txid){
        return depositDao.findByAddressAndTxid(address,txid);
    }
    
    public MemberDeposit findDepositByTxid(String txid){
        return depositDao.findByTxid(txid);
    }

    public int decreaseFrozen(Long walletId,BigDecimal amount){
        return memberWalletDao.decreaseFrozen(walletId,amount);
    }

    public void increaseBalance(Long walletId,BigDecimal amount){
        memberWalletDao.increaseBalance(walletId,amount);
    }

    /**
     * 用户质押：资金账户余额 → 质押钱包锁定余额（直接锁定，无中间可用余额环节）
     * 资金不足由 SQL UPDATE WHERE 条件原子拦截
     *
     * @param memberId 用户ID
     * @param coinUnit 质押币种
     * @param amount   质押金额
     * @return 操作结果，code=0 表示成功
     */
    /**
     * USDT 闪兑为指定币种：扣减资金账户 USDT，按现货价增加目标币种余额（IDO 预售等场景）
     *
     * @param memberId       用户ID
     * @param targetCoinUnit 目标币种 unit，如 IBIT
     * @param usdtAmount     支付的 USDT 数量
     * @param price          目标币种对 USDT 单价（1 目标币 = price USDT）
     * @return 兑换得到的目标币数量放在 data 字段
     */
    @Transactional(rollbackFor = Exception.class)
    public MessageResult flashSwapUsdtToCoin(Long memberId, String targetCoinUnit, BigDecimal usdtAmount,
                                             BigDecimal price) {
        if (usdtAmount == null || usdtAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return MessageResult.error("USDT金额必须大于0");
        }
        if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
            return MessageResult.error("行情价格不可用");
        }
        Coin targetCoin = coinDao.findByUnit(targetCoinUnit);
        if (targetCoin == null) {
            return MessageResult.error("目标币种不存在");
        }
        int scale = targetCoin.getWithdrawScale() > 0 ? targetCoin.getWithdrawScale() : 8;
        BigDecimal coinAmount = usdtAmount.divide(price, scale, java.math.RoundingMode.DOWN);
        if (coinAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return MessageResult.error("兑换数量过小");
        }

        MemberWallet usdtWallet = ensureOrCreateMemberWallet(memberId, "USDT");
        if (usdtWallet == null) {
            return MessageResult.error("USDT钱包不存在");
        }
        int deductUsdt = memberWalletDao.decreaseBalance(usdtWallet.getId(), usdtAmount);
        if (deductUsdt <= 0) {
            return MessageResult.error("USDT余额不足");
        }

        MemberWallet coinWallet = ensureOrCreateMemberWallet(memberId, targetCoinUnit);
        if (coinWallet == null) {
            throw new IllegalStateException("无法创建目标币种钱包: " + targetCoinUnit);
        }
        memberWalletDao.increaseBalance(coinWallet.getId(), coinAmount);

        MemberTransaction usdtOut = buildStakingTransferTransaction(memberId, usdtAmount, "USDT", TransactionType.SPOT);
        transactionService.save(usdtOut);
        MemberTransaction coinIn = buildStakingTransferTransaction(memberId, coinAmount, targetCoinUnit, TransactionType.SPOT);
        transactionService.save(coinIn);

        MessageResult ok = MessageResult.success("闪兑成功");
        ok.setData(coinAmount);
        return ok;
    }

    @Transactional(rollbackFor = Exception.class)
    public MessageResult stakeFundToLocked(Long memberId, String coinUnit, BigDecimal amount) {
        // 1. 校验金额合法性
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            return MessageResult.error("质押金额必须大于0");
        }

        // 2. 扣减资金账户余额
        MemberWallet memberWallet = ensureOrCreateMemberWallet(memberId, coinUnit);
        if (memberWallet == null) {
            return MessageResult.error("币种不存在，无法创建资金钱包");
        }
        int deductRet = memberWalletDao.decreaseBalance(memberWallet.getId(), amount);
        if (deductRet <= 0) {
            return MessageResult.error("资金账户余额不足");
        }

        // 3. 增加质押钱包锁定余额（不存在则自动创建）
        StakingWallet stakingWallet = findExistingStakingWallet(memberId, coinUnit);
        if (stakingWallet == null) {
            stakingWallet = buildStakingWallet(memberId, coinUnit, amount);
            stakingWalletDao.save(stakingWallet);
        } else {
            stakingWalletDao.increaseLockedBalance(stakingWallet.getId(), amount);
        }

        // 4. 记录资金流水（STAKING_DEPOSIT：资金账户划出）
        MemberTransaction transaction = buildStakingTransferTransaction(memberId, amount, coinUnit, TransactionType.STAKING_IN);
        transactionService.save(transaction);

        return MessageResult.success("质押成功");
    }

    /**
     * 查询资金钱包，不存在时按 coinUnit 自动创建零余额钱包
     * 币种在系统中不存在时返回 null
     *
     * @param memberId 用户ID
     * @param coinUnit 币种单位
     * @return 资金钱包，币种不存在时返回 null
     */
    private MemberWallet ensureOrCreateMemberWallet(Long memberId, String coinUnit) {
        MemberWallet wallet = findByCoinUnitAndMemberId(coinUnit, memberId);
        if (wallet != null) {
            return wallet;
        }
        // 钱包不存在，按币种自动创建零余额钱包
        Coin coin = coinDao.findByUnit(coinUnit);
        if (coin == null) {
            log.warn("[ensureOrCreateMemberWallet] 币种不存在: coinUnit={}", coinUnit);
            return null;
        }
        wallet = new MemberWallet();
        wallet.setCoin(coin);
        wallet.setMemberId(memberId);
        wallet.setBalance(BigDecimal.ZERO);
        wallet.setFrozenBalance(BigDecimal.ZERO);
        wallet.setAddress("");
        wallet = save(wallet);
        log.info("[ensureOrCreateMemberWallet] 自动创建钱包 memberId={} coinUnit={}", memberId, coinUnit);
        return wallet;
    }

    /** 构建质押划转流水记录 */
    private MemberTransaction buildStakingTransferTransaction(Long memberId, BigDecimal amount,
                                                              String coinUnit, TransactionType type) {
        MemberTransaction transaction = new MemberTransaction();
        transaction.setMemberId(memberId);
        transaction.setAmount(amount);
        transaction.setSymbol(coinUnit);
        transaction.setType(type);
        transaction.setFee(BigDecimal.ZERO);
        transaction.setDiscountFee("0");
        transaction.setRealFee("0");
        transaction.setCreateTime(new Date());
        return transaction;
    }

    /**
     * 质押到期解锁：staking_wallet.locked_balance → member_wallet.balance（直接归还资金账户）
     *
     * @param wallet 用户资金钱包
     * @param amount 解锁金额
     * @return 1 表示成功，0 表示锁定余额不足或质押钱包不存在
     */
    @Transactional(rollbackFor = Exception.class)
    public int releaseFromStaking(MemberWallet wallet, BigDecimal amount) {
        String coinUnit = wallet.getCoin().getUnit();
        StakingWallet stakingWallet = stakingWalletDao.findByMemberIdAndCoinUnit(wallet.getMemberId(), coinUnit);
        if (stakingWallet == null) {
            return 0;
        }

        // 1. 减少质押锁定余额
        int ret = stakingWalletDao.decreaseLockedBalance(stakingWallet.getId(), amount);
        if (ret <= 0) {
            return 0;
        }

        // 2. 归还至资金账户
        memberWalletDao.increaseBalance(wallet.getId(), amount);
        return 1;
    }

    /**
     * 空投审核通过入账：奖励直接发放至 member_wallet.balance
     * 不存在资金钱包时自动创建
     *
     * @param memberId 用户ID
     * @param coinUnit 币种
     * @param amount   奖励金额
     */
    @Transactional(rollbackFor = Exception.class)
    public void creditAirdropToFund(Long memberId, String coinUnit, BigDecimal amount) {
        // 查询资金钱包，不存在则自动创建
        MemberWallet wallet = ensureOrCreateMemberWallet(memberId, coinUnit);
        if (wallet == null) {
            log.warn("[creditAirdropToFund] 币种不存在，无法入账 coinUnit={} memberId={}", coinUnit, memberId);
            return;
        }
        memberWalletDao.increaseBalance(wallet.getId(), amount);
    }

    /**
     * 查询用户所有币种的质押钱包
     *
     * @param memberId 用户ID
     * @return 质押钱包列表
     */
    public List<StakingWallet> getStakingWallets(Long memberId) {
        return stakingWalletDao.findAllByMemberId(memberId);
    }

    /**
     * 查询用户指定币种的质押钱包（staking_wallet 表），无记录时返回零余额对象
     *
     * @param memberId 用户ID
     * @param coinUnit 币种，如 IBIT
     * @return 质押钱包
     */
    /**
     * 查询已存在的质押钱包（忽略币种大小写）
     */
    private StakingWallet findExistingStakingWallet(Long memberId, String coinUnit) {
        String unit = coinUnit != null ? coinUnit.trim() : "";
        if (!StringUtils.hasText(unit)) {
            return null;
        }
        StakingWallet w = stakingWalletDao.findByMemberIdAndCoinUnitIgnoreCase(memberId, unit);
        if (w == null) {
            w = stakingWalletDao.findByMemberIdAndCoinUnit(memberId, unit);
        }
        return w;
    }

    public StakingWallet findStakingWallet(Long memberId, String coinUnit) {
        StakingWallet w = findExistingStakingWallet(memberId, coinUnit);
        if (w != null) {
            return w;
        }
        String unit = coinUnit != null ? coinUnit.trim() : "";
        StakingWallet empty = new StakingWallet();
        empty.setMemberId(memberId);
        empty.setCoinUnit(unit);
        empty.setLockedBalance(BigDecimal.ZERO);
        return empty;
    }

    /** 构建质押钱包初始记录（首次质押时自动创建） */
    private StakingWallet buildStakingWallet(Long memberId, String coinUnit, BigDecimal lockedAmount) {
        StakingWallet w = new StakingWallet();
        w.setMemberId(memberId);
        w.setCoinUnit(coinUnit);
        w.setLockedBalance(lockedAmount);
        return w;
    }
    
    public void thawBalance(Long walletId,BigDecimal amount) {
    	memberWalletDao.thawBalance(walletId, amount);
    }
    
    public int unfreezeLess(){
        return memberWalletDao.unfreezeLess();
    }
    
    public int unfreezeMore(){
        return memberWalletDao.unfreezeMore();
    }
    
    
//    public int initSuperPaterner(long memberId){
//        return memberWalletDao.initSuperPaterner(memberId);
//    }
    
    public int dropWeekTable(int weekDay){
        return memberWalletDao.dropWeekTable(weekDay);
    }
    
    public int createWeekTable(int weekDay){
        return memberWalletDao.createWeekTable(weekDay);
    }

    public BigDecimal getWalletBalanceAmount(String coinId,int week){
        return memberWalletDao.getWalletBalanceAmount(coinId,week);
    }

    public List<MemberWallet> geteveryBHB(String coinName,int week){
        return memberWalletDao.geteveryBHB(coinName,week);
    }


    //更新团队钱包
    public int updateTeamWallet(BigDecimal teamBalance,long teamId){
        return memberWalletDao.updateTeamWallet(teamBalance,teamId);
    }

    /**
     * 根据 coinId和会员ID查询会员账户信息
     * @param coinId
     * @param memberId
     * @return
     */
    public MemberWallet getMemberWalletByCoinAndMemberId(String coinId, long memberId) {
        return memberWalletDao.getMemberWalletByCoinAndMemberId(coinId,memberId);
    }

    /**
     * 根据用户ID和coinID更新用户钱包
     *
     */
    @Transactional
    public int updateByMemberIdAndCoinId(long memberId,String coinId,BigDecimal balance){
        return memberWalletDao.updateByMemberIdAndCoinId(memberId,coinId,balance);
    }

    /**
     * 增加用户BHB钱包余额
     * @param mineAmount
     * @param memberId
     * @return
     */
    public int increaseBalanceForBHB(BigDecimal mineAmount,Long memberId) {
       return  memberWalletDao.increaseBalanceForBHB(mineAmount,memberId);
    }


    /**
     * 查询待释放BHB大于500的
     */
    public List<MemberWallet> findUnfreezeGTE(){
        return  memberWalletDao.findUnfreezeGTE();
    }
    /**
     * 查询待释放BHB大于500的
     */
    public List<MemberWallet> findUnfreezeLTE(){
        return  memberWalletDao.findUnfreezeLTE();
    }


    public int updateBalanceByIdAndAmount (long id,double amount){
        return memberWalletDao.updateBalanceByIdAndAmount(id,amount);
    }

    /**
     * 增加冻结资产（与余额无关）
     * @param id
     * @param amount
     */
	public void increaseFrozen(Long id, BigDecimal amount) {
		memberWalletDao.increaseFrozen(id, amount);
	}

    /**
     * 增加待释放资产（与余额无关）
     * @param id
     * @param amount
     */
    @Transactional
    public void increaseToRelease(Long id, BigDecimal amount) {
        memberWalletDao.increaseToRelease(id, amount);
    }

    /**
     * 减少待释放资产（与余额无关）
     * @param id
     * @param amount
     */
    @Transactional
    public void decreaseToRelease(Long id, BigDecimal amount) {
        memberWalletDao.decreaseToRelease(id, amount);
    }
}
