package com.hfkj.service.merchant.impl;

import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.security.UserCenter;
import com.hfkj.common.utils.DateUtil;
import com.hfkj.dao.BsMerchantAccountMapper;
import com.hfkj.entity.BsMerchantAccount;
import com.hfkj.entity.BsMerchantAccountExample;
import com.hfkj.entity.BsMerchantAccountRecord;
import com.hfkj.entity.BsOrderRefund;
import com.hfkj.service.merchant.BsMerchantAccountRecordService;
import com.hfkj.service.merchant.BsMerchantAccountService;
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.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * @className: BsMerchantAccountServiceImpl
 * @author: HuRui
 * @date: 2024/7/2
 **/
@Service("merchantAccountService")
public class BsMerchantAccountServiceImpl implements BsMerchantAccountService {
    @Resource
    private BsMerchantAccountMapper merchantAccountMapper;
    @Resource
    private BsMerchantAccountRecordService merchantAccountRecordService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private UserCenter userCenter;
    private final String LOCK_KEY = "MERCHANT_ACCOUNT_LOCK_";
    @Override
    public void editData(BsMerchantAccount 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());
            merchantAccountMapper.insert(account);
        } else {
            merchantAccountMapper.updateByPrimaryKey(account);
        }
    }

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

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

                BsMerchantAccountRecord record = new BsMerchantAccountRecord();
                record.setMerchantAccountId(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());
                merchantAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

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

                BsMerchantAccountRecord record = new BsMerchantAccountRecord();
                record.setMerchantAccountId(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"));
                merchantAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

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

                BsMerchantAccountRecord record = new BsMerchantAccountRecord();
                record.setMerchantAccountId(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());
                merchantAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

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


}
