package com.hotwj.platform.pay.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.hotwj.platform.pay.domain.PayWallet;
import com.hotwj.platform.pay.domain.PayWalletTransaction;
import com.hotwj.platform.pay.domain.bo.PayWalletBatchRechargeBo;
import com.hotwj.platform.pay.domain.bo.PayWalletBo;
import com.hotwj.platform.pay.domain.bo.PayWalletFreezeBo;
import com.hotwj.platform.pay.domain.vo.PayCompanyWalletBalanceVo;
import com.hotwj.platform.pay.domain.vo.PayWalletVo;
import com.hotwj.platform.pay.mapper.PayWalletMapper;
import com.hotwj.platform.pay.mapper.PayWalletTransactionMapper;
import com.hotwj.platform.pay.service.IPayWalletService;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Set;

/**
 * 会员钱包Service业务层处理
 *
 * @author shihongwei
 * @date 2026-05-08
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class PayWalletServiceImpl implements IPayWalletService {

    private static final Long COMPANY_WALLET_TYPE = 2L;
    private static final Long WALLET_BIZ_TYPE_ADMIN_RECHARGE = 2L;
    private static final Long WALLET_FREEZE_STATUS_NORMAL = 0L;
    private static final Long WALLET_FREEZE_STATUS_FROZEN = 1L;

    private final PayWalletMapper baseMapper;
    private final PayWalletTransactionMapper payWalletTransactionMapper;

    /**
     * 查询会员钱包
     *
     * @param id 主键
     * @return 会员钱包
     */
    @Override
    public PayWalletVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询会员钱包列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 会员钱包分页列表
     */
    @Override
    public TableDataInfo<PayWalletVo> queryPageList(PayWalletBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PayWallet> lqw = buildQueryWrapper(bo);
        Page<PayWalletVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public TableDataInfo<PayCompanyWalletBalanceVo> queryCompanyWalletPage(String keyword, PageQuery pageQuery) {
        Page<PayCompanyWalletBalanceVo> page = baseMapper.selectCompanyWalletPage(pageQuery.build(), keyword);
        return TableDataInfo.build(page);
    }

    /**
     * 查询符合条件的会员钱包列表
     *
     * @param bo 查询条件
     * @return 会员钱包列表
     */
    @Override
    public List<PayWalletVo> queryList(PayWalletBo bo) {
        LambdaQueryWrapper<PayWallet> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PayWallet> buildQueryWrapper(PayWalletBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PayWallet> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(PayWallet::getId);
        lqw.eq(bo.getUserId() != null, PayWallet::getUserId, bo.getUserId());
        lqw.eq(bo.getBalance() != null, PayWallet::getBalance, bo.getBalance());
        lqw.eq(bo.getTotalExpense() != null, PayWallet::getTotalExpense, bo.getTotalExpense());
        lqw.eq(bo.getTotalRecharge() != null, PayWallet::getTotalRecharge, bo.getTotalRecharge());
        lqw.eq(bo.getFreezePrice() != null, PayWallet::getFreezePrice, bo.getFreezePrice());
        lqw.eq(bo.getWalletType() != null, PayWallet::getWalletType, bo.getWalletType());
        lqw.eq(bo.getFreezeStatus() != null, PayWallet::getFreezeStatus, bo.getFreezeStatus());
        lqw.like(StringUtils.isNotBlank(bo.getCreateByName()), PayWallet::getCreateByName, bo.getCreateByName());
        lqw.like(StringUtils.isNotBlank(bo.getUpdateByName()), PayWallet::getUpdateByName, bo.getUpdateByName());
        lqw.eq(bo.getIsDeleted() != null, PayWallet::getIsDeleted, bo.getIsDeleted());
        return lqw;
    }

    /**
     * 新增会员钱包
     *
     * @param bo 会员钱包
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(PayWalletBo bo) {
        PayWallet add = MapstructUtils.convert(bo, PayWallet.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改会员钱包
     *
     * @param bo 会员钱包
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(PayWalletBo bo) {
        PayWallet update = MapstructUtils.convert(bo, PayWallet.class);
        PayWallet current = baseMapper.selectById(update.getId());
        if (current == null) {
            throw new ServiceException("钱包不存在");
        }
        if (update.getFreezeStatus() == null) {
            update.setFreezeStatus(current.getFreezeStatus());
        }
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    @Override
    public Boolean changeFreezeStatus(PayWalletFreezeBo bo) {
        if (!WALLET_FREEZE_STATUS_NORMAL.equals(bo.getFreezeStatus()) && !WALLET_FREEZE_STATUS_FROZEN.equals(bo.getFreezeStatus())) {
            throw new ServiceException("冻结状态取值不正确");
        }
        PayWallet wallet = baseMapper.selectById(bo.getWalletId());
        if (wallet == null) {
            throw new ServiceException("钱包不存在");
        }
        wallet.setFreezeStatus(bo.getFreezeStatus());
        return baseMapper.updateById(wallet) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PayWallet entity) {
        if (entity.getFreezeStatus() == null) {
            entity.setFreezeStatus(WALLET_FREEZE_STATUS_NORMAL);
        }
        if (!WALLET_FREEZE_STATUS_NORMAL.equals(entity.getFreezeStatus()) && !WALLET_FREEZE_STATUS_FROZEN.equals(entity.getFreezeStatus())) {
            throw new ServiceException("冻结状态取值不正确");
        }
    }

    /**
     * 校验并批量删除会员钱包信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer batchRechargeCompanyWallet(PayWalletBatchRechargeBo bo) {
        Set<Long> companyIds = parseCompanyIds(bo.getCompanyIds());
        if (companyIds.isEmpty()) {
            throw new ServiceException("企业ids不能为空");
        }
        BigDecimal amount = bo.getAmount().setScale(2, RoundingMode.HALF_UP);
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("充值金额必须大于0");
        }
        String batchBizId = "BRC" + IdUtil.getSnowflakeNextIdStr();
        for (Long companyId : companyIds) {
            PayWallet wallet = getOrCreateCompanyWallet(companyId);
            ensureWalletNotFrozen(wallet, "钱包已冻结，无法充值");
            BigDecimal balance = wallet.getBalance() == null ? BigDecimal.ZERO : wallet.getBalance();
            BigDecimal totalRecharge = wallet.getTotalRecharge() == null ? BigDecimal.ZERO : wallet.getTotalRecharge();
            wallet.setBalance(balance.add(amount));
            wallet.setTotalRecharge(totalRecharge.add(amount));
            if (baseMapper.updateById(wallet) <= 0) {
                throw new ServiceException("更新企业钱包余额失败，企业ID: " + companyId);
            }

            PayWalletTransaction transaction = new PayWalletTransaction();
            transaction.setWalletId(wallet.getId());
            transaction.setBizType(WALLET_BIZ_TYPE_ADMIN_RECHARGE);
            transaction.setBizId(batchBizId);
            transaction.setNo(buildWalletTransactionNo());
            transaction.setTitle("总部批量充值");
            transaction.setPrice(amount);
            transaction.setBalance(wallet.getBalance());
            transaction.setRemark(bo.getRemark());
            if (payWalletTransactionMapper.insert(transaction) <= 0) {
                throw new ServiceException("写入钱包流水失败，企业ID: " + companyId);
            }
        }
        return companyIds.size();
    }

    private PayWallet getOrCreateCompanyWallet(Long companyId) {
        PayWallet wallet = baseMapper.selectOne(Wrappers.<PayWallet>lambdaQuery()
                .eq(PayWallet::getUserId, companyId)
                .eq(PayWallet::getWalletType, COMPANY_WALLET_TYPE)
                .last("limit 1"));
        if (wallet != null) {
            return wallet;
        }
        wallet = new PayWallet();
        wallet.setUserId(companyId);
        wallet.setWalletType(COMPANY_WALLET_TYPE);
        wallet.setBalance(BigDecimal.ZERO);
        wallet.setTotalExpense(BigDecimal.ZERO);
        wallet.setTotalRecharge(BigDecimal.ZERO);
        wallet.setFreezePrice(BigDecimal.ZERO);
        wallet.setFreezeStatus(WALLET_FREEZE_STATUS_NORMAL);
        if (baseMapper.insert(wallet) <= 0) {
            throw new ServiceException("创建企业钱包失败，企业ID: " + companyId);
        }
        return wallet;
    }

    private void ensureWalletNotFrozen(PayWallet wallet, String message) {
        if (wallet != null && WALLET_FREEZE_STATUS_FROZEN.equals(wallet.getFreezeStatus())) {
            throw new ServiceException(message);
        }
    }

    private Set<Long> parseCompanyIds(String companyIds) {
        List<String> idList = StrUtil.splitTrim(StrUtil.blankToDefault(companyIds, ""), ',');
        Set<Long> result = new LinkedHashSet<>();
        for (String id : idList) {
            if (StrUtil.isBlank(id)) {
                continue;
            }
            try {
                result.add(Long.valueOf(id));
            } catch (NumberFormatException e) {
                throw new ServiceException("企业ID格式不正确: " + id);
            }
        }
        return result;
    }

    private String buildWalletTransactionNo() {
        return "WT" + IdUtil.getSnowflakeNextIdStr();
    }
}
