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.utils.DateUtil;
import com.hfkj.dao.BsMerchantChainBrandAccountMapper;
import com.hfkj.entity.*;
import com.hfkj.service.merchant.BsMerchantChainBrandAccountRecordService;
import com.hfkj.service.merchant.BsMerchantChainBrandAccountService;
import com.hfkj.service.merchant.BsMerchantService;
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;

/**
 * @className: BsMerchantChainBrandAccountServiceImpl
 * @author: HuRui
 * @date: 2024/8/14
 **/
@Service("merchantChainBrandAccountService ")
public class BsMerchantChainBrandAccountServiceImpl implements BsMerchantChainBrandAccountService {
    @Resource
    private BsMerchantChainBrandAccountMapper merchantChainBrandAccountMapper;
    @Resource
    private BsMerchantChainBrandAccountRecordService merchantChainBrandAccountRecordService;
    @Resource
    private BsMerchantService merchantService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private final String LOCK_KEY = "MER_CHAIN_BRAND_ACCOUNT_LOCK_";
    @Override
    public void editData(BsMerchantChainBrandAccount data) {
        data.setUpdateTime(new Date());
        if (data.getId() == null) {
            data.setCreateTime(new Date());
            merchantChainBrandAccountMapper.insert(data);
        } else {
            merchantChainBrandAccountMapper.updateByPrimaryKey(data);
        }
    }

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

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

                BsMerchantChainBrandAccountRecord record = new BsMerchantChainBrandAccountRecord();
                record.setMerChainBrandAccountId(account.getId());
                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());
                merchantChainBrandAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

    @Override
    public void consume(Long chainBrandId,String merNo, BigDecimal amount, Map<String, Object> otherParam) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+chainBrandId;
        // 获取锁
        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, "余额不足");
            }*/
                // 查询账户
                BsMerchantChainBrandAccount account = getAccount(chainBrandId);
                // 变更前金额
                BigDecimal beforeAmount = account.getAmount();
                // 计算消费后金额
                account.setAmount(account.getAmount().subtract(amount));
                // 累积消费金额
                account.setAmountConsume(account.getAmountConsume().add(amount));
                editData(account);
                // 变更后金额
                BigDecimal afterAmount = account.getAmount();

                // 查询商户信息
                BsMerchant merchant = merchantService.getMerchant(merNo);

                BsMerchantChainBrandAccountRecord record = new BsMerchantChainBrandAccountRecord();
                record.setMerChainBrandAccountId(account.getId());
                record.setMerId(merchant.getId());
                record.setMerNo(merchant.getMerNo());
                record.setMerName(merchant.getMerName());
                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"));
                merchantChainBrandAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

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

                // 查询商户信息
                BsMerchant merchant = merchantService.getMerchant(merNo);

                BsMerchantChainBrandAccountRecord record = new BsMerchantChainBrandAccountRecord();
                record.setMerChainBrandAccountId(account.getId());
                record.setMerId(merchant.getId());
                record.setMerNo(merchant.getMerNo());
                record.setMerName(merchant.getMerName());
                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());
                merchantChainBrandAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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