package com.ruoyi.cai.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cai.domain.*;
import com.ruoyi.cai.dto.admin.vo.AccountAdminVo;
import com.ruoyi.cai.enums.AccountBusinessEnum;
import com.ruoyi.cai.enums.AccountChangeEnum;
import com.ruoyi.cai.enums.SystemConfigEnum;
import com.ruoyi.cai.manager.IdManager;
import com.ruoyi.cai.manager.SystemConfigManager;
import com.ruoyi.cai.mapper.AccountMapper;
import com.ruoyi.cai.pay.RechargeTypeEnum;
import com.ruoyi.cai.service.*;
import com.ruoyi.cai.util.NumCaUtil;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.transform.Source;
import java.math.BigDecimal;

/**
 * 用户账户Service业务层处理
 *
 * @author 77
 * @date 2023-12-23
 */
@Service
@Slf4j
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {

    @Autowired
    private ConsumeLogService consumeLogService;
    @Autowired
    private UserService userService;
    @Autowired
    private AccountChangeLogService accountChangeLogService;
    @Autowired
    private SystemConfigManager systemConfigManager;


    @Override
    public Account getByUserId(Long userId) {
        return this.getOne(Wrappers.lambdaQuery(Account.class).eq(Account::getUserId,userId).last("limit 1"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ConsumeLog decr(ConsumeLog consumeLog, AccountBusinessEnum businessEnum) {
        log.info("开始扣费 consumeLog={}", JSON.toJSONString(consumeLog));
        Long userId = consumeLog.getSourceUserId();
        Long amount = consumeLog.getAmount();

        Account account = this.getByUserId(userId);
        long totalCoin = account.getIncomeCoin() + account.getCoin();
        if(totalCoin < amount){
            throw new ServiceException("余额不足");
        }
        boolean flag = false;
        long coin = -amount; // 消费余额
        long incomeCoin = 0; // 消费收益
        long diff = account.getCoin() - amount;
        // 充值币够用
        if(diff > 0){
            flag = baseMapper.decrCoin(userId, -coin);
        } else { // 充值币不够用
            coin = -account.getCoin();
            incomeCoin = diff;
            boolean decrCoin = baseMapper.decrCoin(userId, -coin);
            boolean decrIncomeCoin = baseMapper.decrIncomeCoin(userId, -diff);
            if(decrCoin && decrIncomeCoin){
                flag = true;
            }
        }
        // 扣费不成功
        if(!flag){
            throw new ServiceException("扣费失败，请重新购买");
        }
        // 开始处理 接收方的费用
        Long targetUserId = consumeLog.getTargetUserId();
        if(targetUserId != null){
            Long anchorAmount = NumCaUtil.coin(amount,consumeLog.getTargetRate());
            consumeLog.setAnchorAmount(anchorAmount);
            baseMapper.incsIncomeCoin(targetUserId,anchorAmount);
        }
        // 记录消费方的流水
        if(coin != 0){
            accountChangeLogService.saveLogNoAdmin(userId,consumeLog.getSourceUsercode(), RechargeTypeEnum.COIN,businessEnum.getSourceEnum(),coin,consumeLog.getTraceId());
        }
        if(incomeCoin != 0){
            accountChangeLogService.saveLogNoAdmin(userId,consumeLog.getSourceUsercode(), RechargeTypeEnum.COIN_INCOME,businessEnum.getSourceEnum(),incomeCoin,consumeLog.getTraceId());
        }
        // 记录接收方的流水
        if(targetUserId != null){
            accountChangeLogService.saveLogNoAdmin(targetUserId,consumeLog.getTargetUsercode(), RechargeTypeEnum.COIN_INCOME,businessEnum.getTargetEnum(),consumeLog.getAnchorAmount(),consumeLog.getTraceId());
        }
        // 获取分销的比例和用户
        consumeLogService.calculateInitFenxiao(consumeLog);
        consumeLogService.save(consumeLog);
        return consumeLog;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long imDesc(User fromUser, User toUser, Long price) {
        Long fromUserId = fromUser.getId();
        Account account = this.getByUserId(fromUserId);
        long totalCoin = account.getIncomeCoin() + account.getCoin();
        if(totalCoin < price){
            throw new ServiceException("余额不足");
        }
        boolean flag = false;
        long coin = -price; // 消费余额
        long incomeCoin = 0; // 消费收益
        long diff = account.getCoin() - price;
        // 充值币够用
        if(diff > 0){
            flag = baseMapper.decrCoin(fromUserId, -coin);
        } else { // 充值币不够用
            coin = -account.getCoin();
            incomeCoin = diff;
            boolean decrCoin = baseMapper.decrCoin(fromUserId, -coin);
            boolean decrIncomeCoin = baseMapper.decrIncomeCoin(fromUserId, -diff);
            if(decrCoin && decrIncomeCoin){
                flag = true;
            }
        }
        // 扣费不成功
        if(!flag){
            throw new ServiceException("扣费失败，请重新购买");
        }
        // 开始处理 接收方的费用
        BigDecimal imRate = systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DAY_MAX_DYNAMIC);
        Long anchorAmount = NumCaUtil.coin(price,imRate);
        baseMapper.incsIncomeCoin(toUser.getId(),anchorAmount);
        Long tractId = IdManager.nextId();
        // 记录消费方的流水
        if(coin != 0){
            accountChangeLogService.saveLogNoAdmin(fromUserId,fromUser.getUsercode(), RechargeTypeEnum.COIN, AccountChangeEnum.USER_IM, coin, tractId);
        }
        if(incomeCoin != 0){
            accountChangeLogService.saveLogNoAdmin(fromUserId,fromUser.getUsercode(), RechargeTypeEnum.COIN_INCOME,AccountChangeEnum.USER_IM,incomeCoin,tractId);
        }
        // 记录接收方的流水
        if(anchorAmount != 0){
            accountChangeLogService.saveLogNoAdmin(toUser.getId(),toUser.getUsercode(), RechargeTypeEnum.COIN_INCOME,AccountChangeEnum.ANCHOR_IM,anchorAmount,tractId);
        }
        return tractId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdraw(Long userId, Long incomeCoin,Long traceId){
        User user = userService.getById(userId);
        Account account = this.getByUserId(userId);
        if(account == null || user == null){
            throw new ServiceException("无效账号");
        }
        if(account.getIncomeCoin() < incomeCoin){
            throw new ServiceException("需"+incomeCoin+"紫贝才可提现");
        }
        boolean incs = baseMapper.decrIncomeCoin(userId, incomeCoin);
        if(!incs){
            throw new ServiceException("需"+incomeCoin+"紫贝才可提现");
        }
        accountChangeLogService.saveLogNoAdmin(user.getId(),user.getUsercode(), RechargeTypeEnum.COIN_INCOME,AccountBusinessEnum.WITHDRAW.getSourceEnum(),incomeCoin,traceId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recharge(ConsumeLog consumeLog){
        log.info("开始扣费 consumeLog={}", JSON.toJSONString(consumeLog));
        Long userId = consumeLog.getSourceUserId();
        Long amount = consumeLog.getAmount();
        User user = userService.getById(userId);
        Account account = this.getByUserId(userId);
        if(account == null || user == null){
            throw new ServiceException("无效账号");
        }
        baseMapper.incsIncomeCoin(userId, amount);
        accountChangeLogService.saveLogNoAdmin(user.getId(),user.getUsercode(), RechargeTypeEnum.COIN,AccountBusinessEnum.RECHARGE.getOneEnum(),amount,consumeLog.getTraceId());
        // 获取分销的比例和用户
        consumeLogService.calculateInitFenxiao(consumeLog);
        consumeLogService.save(consumeLog);
    }


    @Override
    public Page<AccountAdminVo> pageAdmin(PageQuery pageQuery, AccountAdminVo bo) {
        return baseMapper.pageAdmin(pageQuery.build(),bo);
    }

    /**
     * 分销
     */
    @Override
    public void distribution(Long userId, Long amount, AccountChangeEnum accountChangeEnum,Long traceId) {
        User user = userService.getById(userId);
        Account account = this.getByUserId(userId);
        if(account == null || user == null){
            log.error("分销失败,无效账号 userId={}",userId);
            return;
        }
        if(amount == null || accountChangeEnum == null){
            log.error("分销失败，参数错误 amount={},accountChangeEnum={}",amount,accountChangeEnum);
            return;
        }
        baseMapper.incsCoin(userId, amount);
        accountChangeLogService.saveLogNoAdmin(userId,user.getUsercode(), RechargeTypeEnum.COIN_INCOME,accountChangeEnum,amount,traceId);
    }

}
