package com.hfkj.service.agent.impl;

import com.hfkj.common.exception.BaseException;
import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.utils.DateUtil;
import com.hfkj.dao.BsAgentApiAccountMapper;
import com.hfkj.entity.*;
import com.hfkj.service.agent.BsAgentApiAccountRecordService;
import com.hfkj.service.agent.BsAgentApiAccountService;
import com.hfkj.sysenum.merchant.MerchantAccountRecordSourceTypeEnum;
import com.hfkj.sysenum.merchant.MerchantAccountRecordTypeEnum;
import org.apache.commons.collections4.MapUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @className: BsAgentApiAccountServiceImpl
 * @author: HuRui
 * @date: 2024/8/28
 **/
@Service("agentApiAccountService")
public class BsAgentApiAccountServiceImpl implements BsAgentApiAccountService {
    @Resource
    private BsAgentApiAccountMapper agentApiAccountMapper;
    @Resource
    private BsAgentApiAccountRecordService agentApiAccountRecordService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private final String LOCK_KEY = "AGENT_API_ACCOUNT_LOCK_";
    @Override
    public void create(Long agentId) {
        BsAgentApiAccount data = new BsAgentApiAccount();
        data.setAgentId(agentId);
        data.setAmount(new BigDecimal("0"));
        data.setAmountConsume(new BigDecimal("0"));
        data.setStatus(1);
        data.setCreateTime(new Date());
        data.setUpdateTime(new Date());
        agentApiAccountMapper.insert(data);
    }

    @Override
    public void update(BsAgentApiAccount data) {
        data.setUpdateTime(new Date());
        agentApiAccountMapper.updateByPrimaryKey(data);
    }

    @Override
    public BsAgentApiAccount getAccount(Long agentId) {
        BsAgentApiAccountExample example = new BsAgentApiAccountExample();
        example.createCriteria().andAgentIdEqualTo(agentId).andStatusNotEqualTo(0);
        List<BsAgentApiAccount> list = agentApiAccountMapper.selectByExample(example);
        if (list.isEmpty()) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到账户");
        }
        return list.get(0);

    }

    @Override
    public void recharge(Long agentId, BigDecimal amount) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+agentId;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询账户
                BsAgentApiAccount account = getAccount(agentId);
                if (account == null) {
                    throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的交易账户");
                }
                // 变更前金额
                BigDecimal beforeAmount = account.getAmount();
                // 计算金额
                account.setAmount(account.getAmount().add(amount));
                update(account);
                // 变更后金额
                BigDecimal afterAmount = account.getAmount();

                BsAgentApiAccountRecord record = new BsAgentApiAccountRecord();
                record.setAgentApiAccountId(account.getId());
                record.setAgentId(account.getAgentId());
                record.setType(MerchantAccountRecordTypeEnum.type1.getType());
                record.setTransactionAmount(amount);
                record.setBeforeAmount(beforeAmount);
                record.setAfterAmount(afterAmount);
                record.setSourceType(MerchantAccountRecordSourceTypeEnum.type1.getType());
                try {
                    record.setSourceOrderNo(DateUtil.date2String(new Date(), "yyyyMMddHHmmss"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                record.setSourceContent("充值金额：" + record.getTransactionAmount());
                agentApiAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

            } catch (Exception e) {
                e.printStackTrace();
                // 释放锁
                redisTemplate.delete(lockKey);
            }
        } else {
            Thread.sleep(100);
            recharge(agentId, amount);
        }
    }

    @Override
    public void consume(Long agentId, BigDecimal amount, Map<String, Object> otherParam) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+agentId;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询账户
                BsAgentApiAccount account = getAccount(agentId);
                if (account == null) {
                    throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的交易账户");
                }
                // 余额是否小于消费余额
                if (account.getAmount().compareTo(amount) == -1) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "账户余额不足");
                }
                // 变更前金额
                BigDecimal beforeAmount = account.getAmount();
                // 计算消费后金额
                account.setAmount(account.getAmount().subtract(amount));
                // 累积消费金额
                account.setAmountConsume(account.getAmountConsume().add(amount));
                update(account);
                // 变更后金额
                BigDecimal afterAmount = account.getAmount();

                BsAgentApiAccountRecord record = new BsAgentApiAccountRecord();
                record.setAgentApiAccountId(account.getId());
                record.setAgentId(account.getAgentId());
                record.setType(MerchantAccountRecordTypeEnum.type2.getType());
                record.setTransactionAmount(amount);
                record.setBeforeAmount(beforeAmount);
                record.setAfterAmount(afterAmount);
                record.setSourceType(MapUtils.getInteger(otherParam, "sourceType"));
                record.setSourceId(MapUtils.getLong(otherParam, "sourceId"));
                record.setSourceOrderNo(MapUtils.getString(otherParam, "sourceOrderNo"));
                record.setSourceContent(MapUtils.getString(otherParam, "sourceContent"));
                agentApiAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

            } catch (BaseException e) {
                // 释放锁
                redisTemplate.delete(lockKey);
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, e.getErrorMsg());

            } catch (Exception e) {
                // 释放锁
                redisTemplate.delete(lockKey);
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知错误");
            }
        } else {
            Thread.sleep(100);
            consume(agentId, amount, otherParam);
        }
    }

    @Override
    public void refund(Long agentId, BigDecimal amount, BsOrderRefund orderRefund) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+agentId;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询账户
                BsAgentApiAccount account = getAccount(agentId);
                // 变更前金额
                BigDecimal beforeAmount = account.getAmount();
                // 计算退款后的金额
                account.setAmount(account.getAmount().add(amount));
                // 累积消费金额
                account.setAmountConsume(account.getAmountConsume().subtract(amount));
                update(account);
                // 变更后金额
                BigDecimal afterAmount = account.getAmount();

                BsAgentApiAccountRecord record = new BsAgentApiAccountRecord();
                record.setAgentApiAccountId(account.getId());
                record.setAgentId(account.getAgentId());
                record.setType(MerchantAccountRecordTypeEnum.type1.getType());
                record.setTransactionAmount(amount);
                record.setBeforeAmount(beforeAmount);
                record.setAfterAmount(afterAmount);
                record.setSourceType(MerchantAccountRecordSourceTypeEnum.type3.getType());
                record.setSourceId(orderRefund.getId());
                record.setSourceOrderNo(orderRefund.getRefundOrderNo());
                agentApiAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

            } catch (Exception e) {
                e.printStackTrace();
                // 释放锁
                redisTemplate.delete(lockKey);
            }
        } else {
            Thread.sleep(100);
            refund(agentId, amount, orderRefund);
        }
    }
}
