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.BsAgentMerAccountMapper;
import com.hfkj.entity.*;
import com.hfkj.service.agent.BsAgentMerAccountRecordService;
import com.hfkj.service.agent.BsAgentMerAccountService;
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 javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @className: BsAgentMerAccountServiceImpl
 * @author: HuRui
 * @date: 2024/8/1
 **/
@Service("agentMerAccountService")
public class BsAgentMerAccountServiceImpl implements BsAgentMerAccountService {
    @Resource
    private BsAgentMerAccountMapper agentMerAccountMapper;
    @Resource
    private BsAgentMerAccountRecordService agentMerAccountRecordService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private final String LOCK_KEY = "AGENT_MERCHANT_ACCOUNT_LOCK_";

    @Override
    public void editData(BsAgentMerAccount account) {
        account.setUpdateTime(new Date());
        if (account.getId() == null) {
            account.setAmount(new BigDecimal(0));
            account.setAmountConsume(new BigDecimal(0));
            account.setStatus(1);
            account.setCreateTime(new Date());
            agentMerAccountMapper.insert(account);
        } else {
            agentMerAccountMapper.updateByPrimaryKey(account);
        }
    }

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

    @Override
    public void recharge(Long agentId, String merNo, BigDecimal amount) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+agentId+"_"+merNo;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询账户
                BsAgentMerAccount merAccount = getAccount(agentId,merNo);
                // 变更前金额
                BigDecimal beforeAmount = merAccount.getAmount();
                // 计算金额
                merAccount.setAmount(merAccount.getAmount().add(amount));
                editData(merAccount);
                // 变更后金额
                BigDecimal afterAmount = merAccount.getAmount();

                BsAgentMerAccountRecord record = new BsAgentMerAccountRecord();
                record.setAgentId(agentId);
                record.setAgentMerAccountId(merAccount.getId());
                record.setMerNo(merAccount.getMerNo());
                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());
                agentMerAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

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

                BsAgentMerAccountRecord record = new BsAgentMerAccountRecord();
                record.setAgentId(agentId);
                record.setAgentMerAccountId(merAccount.getId());
                record.setMerNo(merAccount.getMerNo());
                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"));
                agentMerAccountRecordService.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, merNo, amount, otherParam);
        }
    }

    @Override
    public void orderCancel(Long agentId, String merNo, BigDecimal amount, Map<String, Object> otherParam) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+agentId+"_"+merNo;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询账户
                BsAgentMerAccount merAccount = getAccount(agentId, merNo);
                // 变更前金额
                BigDecimal beforeAmount = merAccount.getAmount();
                // 计算消费后金额
                merAccount.setAmount(merAccount.getAmount().add(amount));
                // 累积消费金额
                merAccount.setAmountConsume(merAccount.getAmountConsume().subtract(amount));
                editData(merAccount);
                // 变更后金额
                BigDecimal afterAmount = merAccount.getAmount();

                BsAgentMerAccountRecord record = new BsAgentMerAccountRecord();
                record.setAgentId(agentId);
                record.setAgentMerAccountId(merAccount.getId());
                record.setMerNo(merAccount.getMerNo());
                record.setType(MerchantAccountRecordTypeEnum.type1.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"));
                agentMerAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

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

                BsAgentMerAccountRecord record = new BsAgentMerAccountRecord();
                record.setAgentId(agentId);
                record.setAgentMerAccountId(merAccount.getId());
                record.setMerNo(merAccount.getMerNo());
                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());
                agentMerAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

    @Override
    public boolean isTrade(Long agentId, String merNo, String orderNo) {
        Map<String,Object> param = new HashMap<>();
        param.put("agentId", agentId);
        param.put("merNo", merNo);
        param.put("orderNo", orderNo);
        // 查询订单扣款记录
        List<BsAgentMerAccountRecord> list = agentMerAccountRecordService.getList(param);

        // 结果
        boolean result = false;
        if (!list.isEmpty()) {
            // 是否有交易
            List<BsAgentMerAccountRecord> trade = list
                    .stream().filter(o -> o.getType().equals(MerchantAccountRecordTypeEnum.type2.getType()))
                    .collect(Collectors.toList());
            if (!trade.isEmpty()) {
                result = true;

                // 是否有退款给商户
                List<BsAgentMerAccountRecord> refund = list
                        .stream().filter(o -> o.getType().equals(MerchantAccountRecordTypeEnum.type1.getType()))
                        .collect(Collectors.toList());
                if (!refund.isEmpty()) {
                    // 有退款，为false  不可重复退款给商户
                    result = false;
                }
            }
        }
        return result;
    }

    @Override
    public List<Map<String, Object>> getMerList(Map<String, Object> param) {
        return agentMerAccountMapper.selectMerList(param);
    }

}
