package com.kym.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.github.pagehelper.PageHelper;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.entity.StationAccount;
import com.kym.entity.WithdrawnRecord;
import com.kym.entity.common.PageBean;
import com.kym.entity.queryParams.StationQueryParam;
import com.kym.entity.queryParams.WithdrawnQueryParam;
import com.kym.entity.vo.StationAccountVo;
import com.kym.mapper.StationAccountMapper;
import com.kym.service.StationAccountService;
import com.kym.service.WithdrawnRecordService;
import com.kym.service.cache.KymCache;
import com.kym.service.mybatisplus.MyBaseServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 商户账户表 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2025-02-24
 */
@Service
public class StationAccountServiceImpl extends MyBaseServiceImpl<StationAccountMapper, StationAccount> implements StationAccountService {

    private final WithdrawnRecordService withdrawnRecordService;

    public StationAccountServiceImpl(WithdrawnRecordService withdrawnRecordService) {
        this.withdrawnRecordService = withdrawnRecordService;
    }

    @Override
    public StationAccount getStationAccount(String stationId) {
        return lambdaQuery().eq(StationAccount::getStationId, stationId).one();
    }

    @Override
    public PageBean<StationAccountVo> listStationAccounts(StationQueryParam params) {
        var adminStationIds = KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong());
        if (CommUtil.isEmptyOrNull(params.getStationId()) && CommUtil.isNotEmptyAndNull(adminStationIds)) {
            params.setStationId(adminStationIds.get(0));
        }
        if (CommUtil.isNotEmptyAndNull(params.getStationId()) && CommUtil.isNotEmptyAndNull(adminStationIds) && !adminStationIds.contains(params.getStationId())) {
            params.setStationId(adminStationIds.get(0));
        }

        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        var res = lambdaQuery()
                .eq(CommUtil.isNotEmptyAndNull(params.getStationId()), StationAccount::getStationId, params.getStationId())
                .orderByDesc(StationAccount::getId)
                .list();
        var voList = res.stream().map(item -> {
            var vo = new StationAccountVo();
            BeanUtils.copyProperties(item, vo);
            vo.setStationName(KymCache.INSTANCE.getStationNameById(item.getStationId()));
            return vo;
        }).toList();
        return new PageBean<>(voList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyWithdrawn(WithdrawnQueryParam params) {
        // 金额正数校验，防止负数绕过余额检查反向增加余额
        if (params.getAmount() == null || params.getAmount() <= 0) {
            throw new BusinessException("提现金额必须大于0");
        }
        var stationAccount = getStationAccount(params.getStationId());
        if (stationAccount == null) {
            throw new BusinessException("站点账户不存在");
        }
        // 原子条件扣减：余额不足或并发提现时影响行数为 0，不会把可提现余额扣成负数
        boolean updated = lambdaUpdate()
                .setSql("available_balance = available_balance - {0}, withdrawn_frozen_amount = withdrawn_frozen_amount + {0}", params.getAmount())
                .eq(StationAccount::getStationId, params.getStationId())
                .ge(StationAccount::getAvailableBalance, params.getAmount())
                .update();
        if (!updated) {
            throw new BusinessException("提现金额超出可提现金额！");
        }

        var withdrawnRecord = new WithdrawnRecord()
                .setStationId(params.getStationId())
                .setWithdrawnAmount(params.getAmount());
        withdrawnRecordService.save(withdrawnRecord);
    }
}
