package com.spot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spot.entity.Account;
import com.spot.entity.AccountRecord;
import com.spot.enums.AccountRecordIsChanges;
import com.spot.enums.AccountRecordOperateType;
import com.spot.enums.AccountRecordStatus;
import com.spot.enums.AccountRecordType;
import com.spot.mapper.AccountMapper;
import com.spot.service.AccountRecordService;
import com.spot.service.AccountService;
import com.spot.utils.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 账户服务实现类
 *
 * @author jean
 * @date 2026-05-06
 */
@Slf4j
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private AccountRecordService accountRecordService;

    /**
     * 根据用户ID和币种查询账户
     *
     * @param uid    用户ID
     * @param symbol 币种符号
     * @return 账户对象
     */
    @Override
    public Account getByUidAndSymbol(Long uid, String symbol) {
        return getOne(new LambdaQueryWrapper<Account>()
                .eq(Account::getUid, uid)
                .eq(Account::getSymbol, symbol)
                .last(" LIMIT 1"));
    }

    /**
     * 撤单退币：从冻结余额扣除，增加到可用余额
     *
     * @param accountId    账户ID
     * @param refundAmount 退还金额
     * @return 更新行数
     */
    @Override
    public int refundFromFrozenToAvailable(Long accountId, BigDecimal refundAmount) {
        return accountMapper.refundFromFrozenToAvailable(accountId, refundAmount);
    }

    /**
     * 扣除冻结余额
     *
     * @param accountId    账户ID
     * @param frozenAmount 扣除金额
     * @return 更新行数
     */
    @Override
    public int deductFrozenBalance(Long accountId, BigDecimal frozenAmount) {
        return accountMapper.deductFrozenBalance(accountId, frozenAmount);
    }

    /**
     * 增加可用余额
     *
     * @param accountId       账户ID
     * @param availableAmount 增加金额
     * @return 更新行数
     */
    @Override
    public int addAvailableBalance(Long accountId, BigDecimal availableAmount) {
        return accountMapper.addAvailableBalance(accountId, availableAmount);
    }

    /**
     * 增加冻结余额
     *
     * @param accountId    账户ID
     * @param frozenAmount 增加金额
     * @return 更新行数
     */
    @Override
    public int addFrozenBalance(Long accountId, BigDecimal frozenAmount) {
        return accountMapper.addFrozenBalance(accountId, frozenAmount);
    }

    /**
     * 冻结金额：从可用余额扣除，增加到冻结余额
     *
     * @param accountId    账户ID
     * @param freezeAmount 冻结金额
     * @return 更新行数
     */
    @Override
    public int freezeFromAvailableToFrozen(Long accountId, BigDecimal freezeAmount) {
        return accountMapper.freezeFromAvailableToFrozen(accountId, freezeAmount);
    }

    /**
     * 扣除可用余额
     *
     * @param accountId       账户ID
     * @param availableAmount 扣除金额
     * @return 更新行数
     */
    @Override
    public int deductAvailableBalance(Long accountId, BigDecimal availableAmount) {
        return accountMapper.deductAvailableBalance(accountId, availableAmount);
    }

    /**
     * 获取或初始化现货账户
     * INSERT IGNORE 保证并发安全：多个并发请求同时首次划转时只有一条 INSERT 成功，
     * 其余 IGNORE 静默跳过，再统一查询返回同一条记录。
     *
     * @param uid    用户ID
     * @param symbol 币种符号
     * @return 现货账户对象
     */
    @Override
    public Account getOrCreateAccount(Long uid, String symbol) {
        // INSERT IGNORE：并发安全，重复插入静默跳过
        accountMapper.insertOrIgnore(uid, symbol);
        // 无论新建还是已存在，统一查库获取含自增 id 的完整记录
        return getByUidAndSymbol(uid, symbol);
    }

    /**
     * 查询有冻结余额但无对应活跃委托的孤悬账户
     *
     * @param batchSize 每批次最大返回数量
     * @return 孤悬冻结账户列表
     */
    @Override
    public List<Account> findFrozenAccountsWithoutOrders(int batchSize) {
        return accountMapper.findFrozenAccountsWithoutOrders(batchSize);
    }

    /**
     * 释放孤悬冻结余额：将 cold_money 全量移回 hot_money，同一事务写入解冻流水
     *
     * @param account 待解冻账户
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void releaseOrphanFrozenBalance(Account account) {
        // 1. 将全部冻结余额原子移回可用余额
        int rows = accountMapper.refundFromFrozenToAvailable(account.getId(), account.getColdMoney());
        if (rows == 0) {
            throw new RuntimeException(
                    String.format("孤悬冻结解冻失败（余额已变化或账户异常） - accountId=%d, coldMoney=%s",
                            account.getId(), account.getColdMoney()));
        }

        // 2. 写入解冻流水（account_record）
        accountRecordService.save(buildUnfreezeRecord(account));
    }

    /** 构建解冻流水记录 */
    private AccountRecord buildUnfreezeRecord(Account account) {
        AccountRecord record = new AccountRecord();
        record.setUid(account.getUid());
        record.setAccountId(account.getId());
        record.setSymbol(account.getSymbol());
        record.setAmount(account.getColdMoney());
        record.setType(AccountRecordType.UNFREEZE.getCode());
        record.setOperateType(AccountRecordOperateType.UNFREEZE.getCode());
        record.setStatus(AccountRecordStatus.COMPLETED.getCode());
        // 解冻不改变总余额（cold 转 hot，总量不变）
        record.setIsChanges(AccountRecordIsChanges.NO.getCode());
        record.setSource(Constant.ACCOUNT_RECORD_SOURCE_RELEASE_FROZEN);
        record.setRemark("系统自动解冻：冻结余额无对应活跃委托");
        record.setCtime(LocalDateTime.now());
        return record;
    }
}
