package com.sonic.lion.service.impl;

import com.sonic.lion.dao.AccountBuffDao;
import com.sonic.lion.domain.entity.AccountBuff;
import com.sonic.lion.domain.entity.AccountBuffBill;
import com.sonic.lion.domain.enums.BuffClassifyEnum;
import com.sonic.lion.domain.enums.BuffType;
import com.sonic.lion.domain.enums.InOrOut;
import com.sonic.lion.domain.input.BuffTransferExtend;
import com.sonic.lion.domain.input.BuffTransferTargetInput;
import com.sonic.lion.enums.PayGenrtatorCodeType;
import com.sonic.lion.enums.ToastResultCode;
import com.sonic.lion.service.AccountBuffBillService;
import com.sonic.lion.service.BuffTransferService;
import com.sonic.lion.utils.KeyGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * @author code
 * 转账服务
 */
@Service
public class BuffTransferServiceImpl implements BuffTransferService {

    @Autowired
    private AccountBuffDao accountBuffDao;
    @Autowired
    private AccountBuffBillService accountBuffBillService;

    /**
     * 扣减 来源的 Buff 余额
     *
     * @param extend
     * @param from
     */
    private Long decFromBalance(BuffTransferExtend extend, BuffTransferTargetInput from) {
        AccountBuff fromAccountBuff = getAndInitAccount(from.getUid());
        int n = accountBuffDao.decBalance(fromAccountBuff.getId(), from.getAmount());
        //定义钱包余额不足时的异常码
        ToastResultCode.INSUFFICIENT_BALANCE.check(n != 1);
        //记录内部账单
        Long billId = saveBill(extend, fromAccountBuff, extend.getDesUid(), from.getAmount(), InOrOut.OUT, BuffType.BALANCE);
        return billId;
    }

    /**
     * 保存 流水表
     *
     * @param buffTransferExtend 额外信息
     * @param accountBuff        账户信息
     * @param amount             金额
     * @param inOrOut            加减
     * @param buffType           账户类型
     */
    public Long saveBill(BuffTransferExtend buffTransferExtend, AccountBuff accountBuff, Long from, Long amount, InOrOut inOrOut, BuffType buffType) {
        //操作后总buff
        long afterTotalBuff = accountBuff.getTotalAmount();
        if (inOrOut == InOrOut.IN) {
            afterTotalBuff += amount;
        } else if (inOrOut == InOrOut.OUT) {
            afterTotalBuff -= amount;
        }
        AccountBuffBill bill = AccountBuffBill.builder()
                .platform("Epal")
                .billNo(KeyGenerator.instance().generatorUniqueKey(PayGenrtatorCodeType.ACCOUNT_BILL))
                .accountId(accountBuff.getId())
                .uid(accountBuff.getUid())
                .desUid(from)
                .buff(amount)
                .bizType(buffTransferExtend.getBizType())
                .extend(buffTransferExtend.getExtend())
                .payChannel(buffTransferExtend.getPayChannel())
                .tradeNo(buffTransferExtend.getTradeNo())
                .bizNo(buffTransferExtend.getBizNo())
                .bizNoRelationNo(buffTransferExtend.getBizNoRelationNo())
                .balance(afterTotalBuff)
                .inOrOut(inOrOut)
                .buffType(buffType)
                .reason(buffTransferExtend.getReason())
                .createTime(LocalDateTime.now())
                .buffClassify(BuffClassifyEnum.getBuffClassify(buffTransferExtend.getBizType(), inOrOut))
                .build();
        accountBuffBillService.save(bill);
        return bill.getId();
    }

    /**
     * 获取账户 如果没有 新增一个 余额为 0 的账户
     *
     * @param uid
     * @return
     */
    @Override
    public AccountBuff getAndInitAccount(Long uid) {
        AccountBuff accountBuff = accountBuffDao.selectByUid(uid);
        if (accountBuff == null) {
            //先初始化该渠道资金账户
            accountBuff = initAccount(uid);
        }
        return accountBuff;
    }

    /**
     * 初始化 账户
     *
     * @param uid
     * @return
     */
    private AccountBuff initAccount(Long uid) {
        AccountBuff accountBuff = AccountBuff.builder()
                .uid(uid)
                .status(AccountBuff.Status.ENABLE)
                .balance(0L)
                .withdrawableIncome(0L)
                .awaitingIncome(0L)
                .frozenIncome(0L)
                .build();
        accountBuffDao.insert(accountBuff);
        return accountBuff;
    }
}
