package com.fs.company.service.impl;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.util.ObjectUtil;
import com.fs.common.constant.FsConstants;
import com.fs.common.core.domain.R;
import com.fs.common.core.redis.RedisCache;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import com.fs.company.constant.PaymentStatus;
import com.fs.company.domain.Company;
import com.fs.company.domain.CompanyMoneyLogs;
import com.fs.company.domain.CompanyRechargeOrder;
import com.fs.company.dto.RechargeDTO;
import com.fs.company.mapper.CompanyMapper;
import com.fs.company.mapper.CompanyMoneyLogsMapper;
import com.fs.company.mapper.CompanyRechargeOrderMapper;
import com.fs.company.service.CompanyRechargeOrderService;
import com.fs.company.vo.CompanyRechargeExportVO;
import com.fs.company.vo.CompanyRechargeVO;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.fs.company.mapper.CompanyRechargeMapper;
import com.fs.company.domain.CompanyRecharge;
import com.fs.company.service.ICompanyRechargeService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 充值Service业务层处理
 *
 * @author fs
 * @date 2021-10-04
 */
@Slf4j
@Service
public class CompanyRechargeServiceImpl implements ICompanyRechargeService
{
    @Autowired
    private CompanyRechargeMapper companyRechargeMapper;
    @Autowired
    private CompanyMoneyLogsMapper moneyLogsMapper;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private CompanyRechargeOrderService companyRechargeOrderService;
    @Qualifier("redissonClient")
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisCache redisCache;

    /**
     * 查询充值
     *
     * @param rechargeId 充值ID
     * @return 充值
     */
    @Override
    public CompanyRecharge selectCompanyRechargeById(Long rechargeId)
    {
        return companyRechargeMapper.selectCompanyRechargeById(rechargeId);
    }

    /**
     * 查询充值列表
     *
     * @param companyRecharge 充值
     * @return 充值
     */
    @Override
    public List<CompanyRecharge> selectCompanyRechargeList(CompanyRecharge companyRecharge)
    {
        return companyRechargeMapper.selectCompanyRechargeList(companyRecharge);
    }

    /**
     * 新增充值
     *
     * @param companyRecharge 充值
     * @return 结果
     */
    @Override
    public int insertCompanyRecharge(CompanyRecharge companyRecharge)
    {
        companyRecharge.setCreateTime(DateUtils.getNowDate());
        return companyRechargeMapper.insertCompanyRecharge(companyRecharge);
    }

    /**
     * 修改充值
     *
     * @param companyRecharge 充值
     * @return 结果
     */
    @Override
    public int updateCompanyRecharge(CompanyRecharge companyRecharge)
    {
        return companyRechargeMapper.updateCompanyRecharge(companyRecharge);
    }

    @Override
    public R syncUpdateRedisCompanyRecharge(Company company, BigDecimal rechargeMoney, Integer type) {
        if(company.getCompanyId() == null){
            log.error("公司充值/扣款-审核-同步更新到缓存，参数错误，公司id：{}, 充值/扣款余额：{}，类型：{}", null, rechargeMoney, type);
            return R.error("公司id为空");
        }

        // 公司红包真实余额key
        String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + company.getCompanyId();

        // 加锁，与看课发放红包的加锁保持一致
        RLock lock = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + company.getCompanyId());
        boolean lockAcquired = false;
        try {
            BigDecimal newMoney = company.getMoney();

            // 尝试加锁
            lockAcquired = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (lockAcquired) {
                BigDecimal redisMoney;
                // 获取当前余额
                String moneyStr = redisCache.getCacheObject(companyMoneyKey);
                if (StringUtils.isNotEmpty(moneyStr)) {
                    redisMoney = new BigDecimal(moneyStr);
                } else {
                    redisMoney = company.getMoney();
                }

                if(type == 1){
                    // 充值
                    newMoney = redisMoney.add(rechargeMoney);
                } else {
                    newMoney = redisMoney.subtract(rechargeMoney);
                }

                redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
            }
            return R.ok().put("newMoney", newMoney);
        } catch (Exception e) {
            log.error("公司充值/扣款-审核-同步更新到缓存，参数错误，请求异常，异常信息：{}", e.getMessage(), e);
            return R.error("审核失败，请重试");
        } finally {
            if (lockAcquired && lock.isHeldByCurrentThread()) {
                try {
                    lock.unlock();
                } catch (IllegalMonitorStateException e) {
                    log.warn("尝试释放非当前线程持有的锁: companyId：{}", company.getCompanyId());
                }
            }
        }
    }

    @Override
    public List<CompanyRechargeVO> selectCompanyRechargeListVO(CompanyRechargeVO companyRecharge) {
        return companyRechargeMapper.selectCompanyRechargeListVO(companyRecharge);
    }
    /**
     * 批量删除充值
     *
     * @param rechargeIds 需要删除的充值ID
     * @return 结果
     */
    @Override
    public int deleteCompanyRechargeByIds(Long[] rechargeIds)
    {
        return companyRechargeMapper.deleteCompanyRechargeByIds(rechargeIds);
    }

    /**
     * 删除充值信息
     *
     * @param rechargeId 充值ID
     * @return 结果
     */
    @Override
    public int deleteCompanyRechargeById(Long rechargeId) {
        return companyRechargeMapper.deleteCompanyRechargeById(rechargeId);
    }

    @Override
    public List<CompanyRechargeVO> selectCompanyRechargeVOList(CompanyRecharge companyRecharge) {
        return companyRechargeMapper.selectCompanyRechargeVOList(companyRecharge);
    }

    @Override
    public CompanyRecharge selectCompanyRechargeByNo(String no) {
        return companyRechargeMapper.selectCompanyRechargeByNo(no);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public R payNotify(CompanyRecharge recharge) {
        //修改状态
        recharge.setPayTime(new Date());
        recharge.setStatus(1);
        companyRechargeMapper.updateCompanyRecharge(recharge);
        Company company=companyMapper.selectCompanyByIdForUpdate(recharge.getCompanyId());
        company.setMoney(company.getMoney().add(recharge.getMoney()));
        //写入日志
        CompanyMoneyLogs log=new CompanyMoneyLogs();
        log.setCompanyId(recharge.getCompanyId());
        log.setMoney(recharge.getMoney());
        log.setRemark("充值金额:"+recharge.getMoney()+"元");
        log.setCreateTime(new Date());
        log.setLogsType(3);
        log.setBalance(company.getMoney());
        moneyLogsMapper.insertCompanyMoneyLogs(log);
        //修改余额

        company.setMoney(company.getMoney().add(recharge.getMoney()));
        companyMapper.updateCompany(company);
        return R.ok();
    }

    @Autowired
    private CompanyRechargeOrderMapper companyRechargeOrderMapper;

    @Override
    public synchronized R payNotify(String orderNo,String transactionId) {
        CompanyRechargeOrder order = companyRechargeOrderMapper.selectByOrderNo(orderNo);

        if(ObjectUtil.equal(order.getPayStatus(), PaymentStatus.SUCCESS.getCode())){
            log.info("订单已支付！重复付款 {} {}", orderNo,transactionId);
            R.ok();
        }
        //修改状态
        order.setPayStatus(PaymentStatus.SUCCESS.getCode());
        order.setTransactionId(transactionId);
        companyRechargeOrderMapper.updateByOrderNo(order);

        Company company=companyMapper.selectCompanyByIdForUpdate(order.getCompanyId());
        //写入日志
        CompanyMoneyLogs log=new CompanyMoneyLogs();
        log.setCompanyId(order.getCompanyId());
        log.setMoney(order.getPayAmount());
        log.setRemark("充值金额:"+order.getPayAmount()+"元");
        log.setCreateTime(new Date());
        log.setLogsType(3);
        log.setBalance(company.getMoney());
        moneyLogsMapper.insertCompanyMoneyLogs(log);
        //修改余额
        company.setMoney(company.getMoney().add(order.getPayAmount()));
        companyMapper.updateCompany(company);
        return R.ok();
    }

    @Override
    public BigDecimal selectCompanyRechargeMoney() {
        return companyRechargeMapper.selectCompanyRechargeMoney();
    }

    @Override
    public List<CompanyRechargeExportVO> selectCompanyRechargeExportList(CompanyRecharge companyRecharge) {
        return companyRechargeMapper.selectCompanyRechargeExportList(companyRecharge);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public CompanyRechargeOrder recharge(RechargeDTO dto) throws Exception {
        CompanyRechargeOrder order = new CompanyRechargeOrder();
        order.setPayAmount(dto.getAmount());
        order.setCompanyId(dto.getCompanyId());
        order.setUserId(dto.getUserId());
        return companyRechargeOrderService.createOrder(order);
    }

    @Override
    public CompanyRechargeOrder queryOrder(String orderNo) {
        return companyRechargeOrderService.queryOrder(orderNo);
    }
}
