package com.hfkj.service.spread.impl;

import com.alibaba.fastjson.JSONObject;
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.common.utils.WxUtils;
import com.hfkj.config.CommonSysConst;
import com.hfkj.dao.BsUserSpreadAccountMapper;
import com.hfkj.entity.*;
import com.hfkj.service.spread.BsUserSpreadAccountRecordService;
import com.hfkj.service.spread.BsUserSpreadAccountService;
import com.hfkj.service.spread.BsUserSpreadPowerService;
import com.hfkj.service.user.BsUserService;
import com.hfkj.sysenum.merchant.MerchantAccountRecordTypeEnum;
import com.hfkj.sysenum.spread.UserSpreadAccountRecordSourceTypeEnum;
import com.hfkj.sysenum.spread.UserSpreadAccountStatusEnum;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
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.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @className: BsUserSpreadAccountServiceImpl
 * @author: HuRui
 * @date: 2025/3/31
 **/
@Service("userSpreadAccountService")
public class BsUserSpreadAccountServiceImpl implements BsUserSpreadAccountService {
    @Resource
    private BsUserSpreadAccountMapper userSpreadAccountMapper;
    @Resource
    private BsUserService userService;
    @Resource
    private BsUserSpreadAccountRecordService userSpreadAccountRecordService;
    @Resource
    private BsUserSpreadPowerService userSpreadPowerService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private static final String LOCK_KEY = "USER_SPREAD_ACCOUNT_LOCK_";
    @Override
    public void create(Long userId,String userPhone) {
        BsUserSpreadAccount account = new BsUserSpreadAccount();
        account.setUserId(userId);
        account.setUserPhone(userPhone);
        account.setAmount(new BigDecimal("0"));
        account.setCashOutAmount(new BigDecimal("0"));
        account.setStatus(1);
        account.setCreateTime(new Date());
        account.setUpdateTime(new Date());
        userSpreadAccountMapper.insert(account);
    }

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

    @Override
    public void freezeUserSpread(Long userId) {
        // 查询账户
        BsUserSpreadAccount account = getDetailByUser(userId);
        if (account == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到账户");
        }
        account.setStatus(UserSpreadAccountStatusEnum.status2.getType());
        update(account);
        // 推广权限
        BsUserSpreadPower userSpreadPower = userSpreadPowerService.getDetailByUser(account.getUserId());
        if (userSpreadPower != null) {
            userSpreadPower.setStatus(UserSpreadAccountStatusEnum.status2.getType());
            userSpreadPowerService.editData(userSpreadPower);
        }
    }

    @Override
    public void unfreezeUserSpread(Long userId) {
        // 查询账户
        BsUserSpreadAccount account = getDetailByUser(userId);
        if (account == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到账户");
        }
        account.setStatus(UserSpreadAccountStatusEnum.status1.getType());
        update(account);
        // 推广权限
        BsUserSpreadPower userSpreadPower = userSpreadPowerService.getDetailByUser(account.getUserId());
        if (userSpreadPower != null) {
            userSpreadPower.setStatus(UserSpreadAccountStatusEnum.status1.getType());
            userSpreadPowerService.editData(userSpreadPower);
        }
    }

    @Override
    public BsUserSpreadAccount getDetailByUser(Long userId) {
        BsUserSpreadAccountExample example = new BsUserSpreadAccountExample();
        example.createCriteria().andUserIdEqualTo(userId).andStatusNotEqualTo(UserSpreadAccountStatusEnum.status0.getType());
        List<BsUserSpreadAccount> list = userSpreadAccountMapper.selectByExample(example);
        if (!list.isEmpty()){
            return list.get(0);
        }
        return null;
    }

    @Override
    public List<BsUserSpreadAccount> getList(Map<String, Object> param) {
        BsUserSpreadAccountExample example = new BsUserSpreadAccountExample();
        example.createCriteria().andStatusNotEqualTo(0);

        example.setOrderByClause("create_time desc");
        return userSpreadAccountMapper.selectByExample(example);
    }

    @Override
    public JSONObject withdraw(Long userId, String openId,BigDecimal amount) throws Exception {
        if (amount.compareTo(new BigDecimal("20")) < 0 || amount.compareTo(new BigDecimal("200")) > 0) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "金额20-200之间");
        }
        // 推广账户
        BsUserSpreadAccount userSpreadAccount = getDetailByUser(userId);
        if (userSpreadAccount == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到账户");
        }
        if (!userSpreadAccount.getStatus().equals(UserSpreadAccountStatusEnum.status1.getType())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "账户已被冻结");
        }
        if (userSpreadAccount.getAmount().compareTo(amount) < 0) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "余额不足");
        }
        if (userSpreadAccountRecordService.withdrawChance(userId) > 5) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "已达每日提现次数上限");
        }
        // 查询用户信息
        BsUser user = userService.getUser(userId);
        if (user == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "用户信息未完善");
        }
        // 提现订单号
        String outBillNo = DateUtil.date2String(new Date(), DateUtil.YMDHMS);
        // 微信商家转账
        JSONObject data = WxUtils.transferBills(openId,outBillNo, amount, "佣金提现");
        // 扣除余账户余额
        Map<String,Object> otherParam = new HashMap<>();
        otherParam.put("sourceContent", "提现"+amount+"元");
        otherParam.put("sourceOrderNo", outBillNo);
        otherParam.put("ext1", data.getString("transferBillNo"));
        minus(userId, amount, UserSpreadAccountRecordSourceTypeEnum.type2, otherParam);

        data.put("appId", CommonSysConst.getSysConfig().getWxMaAppId());
        data.put("mchId", "1614670195");
        return data;
    }

    @Override
    public void cancelWithdraw(String orderNo) throws Exception {
        // 记录
        BsUserSpreadAccountRecord record = userSpreadAccountRecordService.getRecordByOrderNo(orderNo);
        if (record == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到提现记录");
        }
        // 微信商家转账
        WxUtils.cancelTransferBills(orderNo);
    }

    @Override
    public void increase(Long userId, BigDecimal amount, UserSpreadAccountRecordSourceTypeEnum sourceType, Map<String, Object> otherParam) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+userId;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询账户
                BsUserSpreadAccount account = getDetailByUser(userId);
                if (account == null) {
                    throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知账户");
                }
                if (!account.getStatus().equals(UserSpreadAccountStatusEnum.status1.getType())) {
                    throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "账户不可用");
                }
                // 变更前金额
                BigDecimal beforeAmount = account.getAmount();
                // 计算金额
                account.setAmount(account.getAmount().add(amount));
                // 累积提现金额
                if (UserSpreadAccountRecordSourceTypeEnum.type4.getType().intValue() == sourceType.getType()) {
                    account.setCashOutAmount(account.getCashOutAmount().subtract(amount));
                }
                update(account);
                // 变更后金额
                BigDecimal afterAmount = account.getAmount();

                BsUserSpreadAccountRecord record = new BsUserSpreadAccountRecord();
                record.setUserSpreadAccountId(account.getId());
                record.setUserId(account.getUserId());
                record.setUserPhone(account.getUserPhone());
                record.setType(MerchantAccountRecordTypeEnum.type1.getType());
                record.setTransactionAmount(amount);
                record.setBeforeAmount(beforeAmount);
                record.setAfterAmount(afterAmount);
                record.setSourceType(sourceType.getType());
                try {
                    record.setSourceOrderNo(DateUtil.date2String(new Date(), "yyyyMMddHHmmss"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (StringUtils.isNotBlank(MapUtils.getString(otherParam, "sourceContent"))) {
                    record.setSourceContent(MapUtils.getString(otherParam, "sourceContent"));
                }
                if (StringUtils.isNotBlank(MapUtils.getString(otherParam, "ext1"))) {
                    record.setExt1(MapUtils.getString(otherParam, "ext1"));
                }
                userSpreadAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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

    @Override
    public void minus(Long userId, BigDecimal amount, UserSpreadAccountRecordSourceTypeEnum sourceType, Map<String, Object> otherParam) throws Exception {
        // 锁编号
        String lockKey = LOCK_KEY+userId;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询账户
                BsUserSpreadAccount account = getDetailByUser(userId);
                if (account == null) {
                    throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知账户");
                }
                if (!account.getStatus().equals(UserSpreadAccountStatusEnum.status1.getType())) {
                    throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "账户不可用");
                }
                // 变更前金额
                BigDecimal beforeAmount = account.getAmount();
                // 计算金额
                account.setAmount(account.getAmount().subtract(amount));
                // 累积提现金额
                if (UserSpreadAccountRecordSourceTypeEnum.type2.getType().intValue() == sourceType.getType()) {
                    account.setCashOutAmount(account.getCashOutAmount().add(amount));
                }
                update(account);
                // 变更后金额
                BigDecimal afterAmount = account.getAmount();

                BsUserSpreadAccountRecord record = new BsUserSpreadAccountRecord();
                record.setUserSpreadAccountId(account.getId());
                record.setUserId(account.getUserId());
                record.setUserPhone(account.getUserPhone());
                record.setType(MerchantAccountRecordTypeEnum.type2.getType());
                record.setTransactionAmount(amount);
                record.setBeforeAmount(beforeAmount);
                record.setAfterAmount(afterAmount);
                record.setSourceType(sourceType.getType());
                if (StringUtils.isNotBlank(MapUtils.getString(otherParam, "sourceContent"))) {
                    record.setSourceContent(MapUtils.getString(otherParam, "sourceContent"));
                }
                if (StringUtils.isNotBlank(MapUtils.getString(otherParam, "sourceOrderNo"))) {
                    record.setSourceOrderNo(MapUtils.getString(otherParam, "sourceOrderNo"));
                } else {
                    record.setSourceOrderNo(DateUtil.date2String(new Date(), "yyyyMMddHHmmss"));
                }
                if (StringUtils.isNotBlank(MapUtils.getString(otherParam, "ext1"))) {
                    record.setExt1(MapUtils.getString(otherParam, "ext1"));
                }
                userSpreadAccountRecordService.create(record);
                // 释放锁
                redisTemplate.delete(lockKey);

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