package cn.pluss.platform.cash.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.crypto.SecureUtil;
import cn.pluss.platform.ali.AlipayService;
import cn.pluss.platform.cash.CashService;
import cn.pluss.platform.cashAccount.CashAccountService;
import cn.pluss.platform.common.CommonRemarkService;
import cn.pluss.platform.common.RiskBlacklistService;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.fans.FansService;
import cn.pluss.platform.mapper.CashMapper;
import cn.pluss.platform.mapper.FansMapper;
import cn.pluss.platform.mapper.MerchantProfitMapper;
import cn.pluss.platform.merchantProfit.MerchantProfitService;
import cn.pluss.platform.userApp.UserAppService;
import cn.pluss.platform.userInfo.UserInfoService;
import cn.pluss.platform.user.impl.GeneralPushUtil;
import cn.pluss.platform.util.StringUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.util.*;

@Slf4j
@Service("cashService")
public class CashServiceImpl extends ServiceImpl<CashMapper, Cash> implements CashService {

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private CashService self;

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private UserAppService userAppService;

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private UserInfoService userInfoService;

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private CashAccountService cashAccountService;

    @Setter(onMethod_ = {@Autowired})
    private CommonRemarkService remarkService;

    @Setter(onMethod_ = {@Autowired})
    private AlipayService alipayService;

    @Autowired @Lazy
    private MerchantProfitService mpService;

    @Autowired
    private FansService fansService;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private GeneralPushUtil generalPushUtil;

    @Autowired
    private RiskBlacklistService rbService;

    @Resource
    private FansMapper fansMapper;

    @Resource
    private MerchantProfitMapper mpMapper;

    private void checkStatus(Integer userId) {
        RiskBlacklist condition = new RiskBlacklist();
        condition.setUserId(userId);
        RiskBlacklist entity = rbService.getOne(new QueryWrapper<>(condition));

        if (entity != null) {
            throw new MsgException("该账户存在重大违规行为，暂不支持提现，请联系收银呗客服申诉");
        }
    }

    private void checkPayPwd(Cash cash) {
        MsgException.checkNull(cash.getPayPassword(), "缺少支付密码");

        UserApp userApp = userAppService.queryUserAppByToken();
        cash.setUserId(userApp.getUserId());
        UserInfo userInfo = new UserInfo().setId(userApp.getUserId());
        userInfo = userInfoService.getOne(new QueryWrapper<>(userInfo));

        String psdMd5 = SecureUtil.md5(cash.getPayPassword());
        MsgException.checkUnequals(psdMd5, userInfo.getPayPassword(), "支付密码错误");
    }

    @Override
    public void apiSaveCash(Cash cash) {
        if(cash.getCashAmt().compareTo(BigDecimal.valueOf(Cash.MINIMUM_CASH)) < 0) {
            throw new MsgException("提现金额必须大于" + Cash.MINIMUM_CASH + "元");
        }

        UserApp userApp = userAppService.queryUserAppByToken();

        Cash existData = new Cash();
        existData.setUserId(cash.getUserId());
        QueryWrapper<Cash> qWrapper = new QueryWrapper<>(existData);
        qWrapper.orderByDesc("createDt");
        qWrapper.last("limit 1");
        existData = getOne(qWrapper);

        if (existData != null && DateUtil.isSameDay(new Date(), existData.getCreateDt())) {
            throw new MsgException("一天只能提现一次");
        }

        cash.setCashNumber(StringUtil.getBillno());
        cash.setCreateDt(new Date());
        cash.setStatus(0);
        cash.setUserName(userApp.getUserName());
        cash.setMerchantName(userApp.getMerchantName());
        cash.setMerchantCode(userApp.getMerchantCode());

        LambdaQueryWrapper<CashAccount> qWrapper2 = new LambdaQueryWrapper<CashAccount>()
                .eq(CashAccount::getUserId, cash.getUserId())
                .last("limit 1");
        CashAccount cashAccount = cashAccountService.getOne(qWrapper2);
        if (cashAccount != null) {
            cash.setAccountName(cashAccount.getAccountName());
            cash.setAccountNo(cashAccount.getAccountNo());
        } else {
            throw new MsgException("请先完善提现账户信息");
        }

        if (StringUtil.isNotEmpty(userApp.getLogo())) {
            cash.setLogo(userApp.getLogo());
        }

        save(cash);
    }

    @Override
    public void apiSaveCashV2(Cash cash) {
        Date limitDate = null;
        try {
            limitDate = DateUtils.parseDate("2022-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss");
        } catch (ParseException ignored) {
        }

        if (limitDate != null && System.currentTimeMillis() > limitDate.getTime()) {
            throw new MsgException("提现功能维护中");
        }

        checkPayPwd(cash);

        apiSaveCash(cash);

        UserApp userApp = userAppService.queryUserAppByToken();

        Cash existData = new Cash();
        existData.setUserId(cash.getUserId());
        QueryWrapper<Cash> qWrapper = new QueryWrapper<>(existData);
        qWrapper.orderByDesc("createDt");
        qWrapper.last("limit 1");
        existData = getOne(qWrapper);

        if (existData != null && DateUtil.isSameDay(new Date(), existData.getCreateDt())) {
            throw new MsgException("一天只能提现一次");
        }

        cash.setCashNumber(StringUtil.getBillno());
        cash.setCreateDt(new Date());
        cash.setStatus(0);
        cash.setUserName(userApp.getUserName());
        cash.setMerchantName(userApp.getMerchantName());
        cash.setMerchantCode(userApp.getMerchantCode());

        LambdaQueryWrapper<CashAccount> qWrapper2 = new LambdaQueryWrapper<CashAccount>()
                .eq(CashAccount::getUserId, cash.getUserId())
                .last("limit 1");
        CashAccount cashAccount = cashAccountService.getOne(qWrapper2);
        if (cashAccount != null) {
            cash.setAccountName(cashAccount.getAccountName());
            cash.setAccountNo(cashAccount.getAccountNo());
        }

        if (StringUtil.isNotEmpty(userApp.getLogo())) {
            cash.setLogo(userApp.getLogo());
        }

        save(cash);
    }

    @Override
    public Cash cashDetail(Cash cash) {
        UserApp tokenUa = userAppService.queryUserAppByToken();
        cash.setUserId(tokenUa.getUserId());

        checkStatus(tokenUa.getUserId().intValue());

        if(cash.getCashAmt().compareTo(BigDecimal.valueOf(Cash.MINIMUM_CASH)) < 0) {
            throw new MsgException("提现金额必须大于" + Cash.MINIMUM_CASH + "元");
        }

        LambdaQueryWrapper<Cash> qWrapper = Wrappers.lambdaQuery();
        qWrapper.eq(Cash::getUserId, cash.getUserId())
                .orderByDesc(Cash::getCreateDt)
                .last("limit 1");
        Cash existData = getOne(qWrapper);

        //TODO 注释提现限制，后面要取消
       /* if (existData != null && DateUtil.isSameDay(new Date(), existData.getCreateDt())) {
            throw new MsgException("一天只能提现一次");
        }
*/
        LambdaQueryWrapper<CashAccount> qWrapper2 = Wrappers.lambdaQuery();
        qWrapper2.eq(CashAccount::getUserId, cash.getUserId())
                .last("limit 1");
        CashAccount cashAccount = cashAccountService.getOne(qWrapper2);
        if (cashAccount != null) {
            cash.setAccountName(DesensitizedUtil.chineseName(cashAccount.getAccountName()));
            if (cashAccount.getAccountNo().contains("@")) {
                cash.setAccountNo(DesensitizedUtil.email(cashAccount.getAccountNo()));
            } else {
                cash.setAccountNo(DesensitizedUtil.mobilePhone(cashAccount.getAccountNo()));
            }
        } else {
            throw new MsgException("请先补充提现账户信息");
        }

        // ======查询可提现金额
        // 查询商户所有分润
        BigDecimal totalProfit = mpService.getSumValidProfit(cash.getUserId() + "");
        if (totalProfit == null) {
            totalProfit = BigDecimal.ZERO;
        }

        if (!StringUtils.isEmpty(tokenUa.getMerchantCode())) {
            Map<String, Object> map = new HashMap<>();
            map.put("lastMerchantCode", tokenUa.getMerchantCode());
            // 查询可提现粉丝分润
            Double sum = fansService.queryFansSumShareMoney(map);
            if (sum != null) {
                BigDecimal fansProfit = BigDecimal.valueOf(sum);
                totalProfit = totalProfit.add(fansProfit);
            }
        }

        // 查询商户已提现总数
        BigDecimal totalCashAmt = getSumValidCashAmtTotal(cash.getUserId() + "");
        if (totalCashAmt == null) {
            totalCashAmt = BigDecimal.ZERO;
        }
        // 校验提现金额是否充足
        int flag = cash.getCashAmt().compareTo(totalProfit.subtract(totalCashAmt));
        if (flag > 0) {
            throw new MsgException("可提现金额不足！");
        }

        cash.setRate(8);
        cash.setBaseServiceCharge(BigDecimal.valueOf(3));
        cash.setRatioCharge(cash.getCashAmt().multiply(BigDecimal.valueOf(0.08)).setScale(2, RoundingMode.HALF_EVEN));
        cash.setVirTotalCharge(cash.getBaseServiceCharge().add(cash.getRatioCharge()));
        cash.setVirRealCashAmt(cash.getCashAmt().subtract(cash.getVirTotalCharge()).setScale(2, RoundingMode.HALF_EVEN));
        return cash;
    }

    @Override
    public void apiSaveCashV3(Cash cash) {
        UserApp tokenUa = userAppService.queryUserAppByToken();
        cash.setUserId(tokenUa.getUserId());

        checkStatus(tokenUa.getUserId().intValue());

        if(cash.getCashAmt().compareTo(BigDecimal.valueOf(Cash.MINIMUM_CASH)) < 0) {
            throw new MsgException("提现金额必须大于" + Cash.MINIMUM_CASH + "元");
        }

        LambdaQueryWrapper<Cash> qWrapper = Wrappers.lambdaQuery();
        qWrapper.eq(Cash::getUserId, cash.getUserId())
                .orderByDesc(Cash::getCreateDt)
                .last("limit 1");
        Cash existData = getOne(qWrapper);

        //TODO 注释掉限制一天只能提现一次
        /*if (existData != null && DateUtil.isSameDay(new Date(), existData.getCreateDt())) {
            throw new MsgException("一天只能提现一次");
        }*/

        // ======查询可提现金额
        // 查询商户所有分润
        BigDecimal totalProfit = mpService.getSumValidProfit(cash.getUserId() + "");
        totalProfit = totalProfit == null? BigDecimal.ZERO: totalProfit;

        if (!StringUtils.isEmpty(tokenUa.getMerchantCode())) {
            Map<String, Object> map = new HashMap<>();
            map.put("lastMerchantCode", tokenUa.getMerchantCode());
            // 查询可提现粉丝分润
            Double sum = fansService.queryFansSumShareMoney(map);
            if (sum != null) {
                BigDecimal fansProfit = BigDecimal.valueOf(sum);
                totalProfit = totalProfit.add(fansProfit);
            }
        }

        // 查询商户已提现总数
        BigDecimal totalCashAmt = getSumValidCashAmtTotal(cash.getUserId() + "");
        totalCashAmt = totalCashAmt == null? BigDecimal.ZERO: totalCashAmt;

        // 校验提现金额是否充足
        int flag = cash.getCashAmt().compareTo(totalProfit.subtract(totalCashAmt));
        if (flag > 0) {
            throw new MsgException("可提现金额不足！");
        }

        cash.setCashNumber(StringUtil.getBillno());
        cash.setCreateDt(new Date());
        cash.setStatus(Cash.STATUS_CHECKING);
        cash.setUserName(tokenUa.getUserName());
        cash.setMerchantName(tokenUa.getMerchantName());
        cash.setMerchantCode(tokenUa.getMerchantCode());
        cash.setRate(8);
        cash.setBaseServiceCharge(BigDecimal.valueOf(3));
        cash.setRatioCharge(cash.getCashAmt().multiply(BigDecimal.valueOf(0.08)));

        LambdaQueryWrapper<CashAccount> qWrapper2 = Wrappers.lambdaQuery();
        qWrapper2.eq(CashAccount::getUserId, cash.getUserId())
                .last("limit 1");
        CashAccount cashAccount = cashAccountService.getOne(qWrapper2);
        log.info("申请提现的帐号信息：{}", JSONObject.toJSONString(cashAccount));
        if (cashAccount != null) {
            cash.setAccountName(cashAccount.getAccountName());
            cash.setAccountNo(cashAccount.getAccountNo());
        } else {
            throw new MsgException("请先补充提现账户信息");
        }

        if (StringUtil.isNotEmpty(tokenUa.getLogo())) {
            cash.setLogo(tokenUa.getLogo());
        }

        save(cash);
    }

    @Override
    public Cash queryCash(Cash cash) {
        return baseMapper.selectOne(new QueryWrapper<>(cash));
    }

    @Override
    public void updateCash(Cash cash) {
        baseMapper.updateById(cash);
    }

    public void updateUserIdCash(Cash cash) {
        UpdateWrapper<Cash> uWrapper = new UpdateWrapper<>();
        uWrapper.eq("userId", cash.getUserId());
        baseMapper.update(cash, uWrapper);
    }

    @Override
    public void deleteUserIdCash(Cash cash) {
        QueryWrapper<Cash> qWrapper = new QueryWrapper<>();
        qWrapper.eq("userId", cash.getUserId());
        baseMapper.delete(qWrapper);
    }

    @Override
    public <E extends IPage<Cash>> E page(E page, Wrapper<Cash> queryWrapper) {
        Cash cash = queryWrapper.getEntity();
        ((QueryWrapper<Cash>) queryWrapper).eq(StringUtil.isNotEmpty(cash.getType()), "tpc.type", cash.getType());

        ((QueryWrapper<Cash>) queryWrapper).like(StringUtil.isNotEmpty(cash.getUserName()), "tpc.userName", cash.getUserName());

        ((QueryWrapper<Cash>) queryWrapper).eq(StringUtil.isNotEmpty(cash.getMerchantCode()), "tpc.merchantCode", cash.getMerchantCode());

        ((QueryWrapper<Cash>) queryWrapper).like(StringUtil.isNotEmpty(cash.getMerchantName()), "tpc.merchantName", cash.getMerchantName());

        ((QueryWrapper<Cash>) queryWrapper).eq(StringUtil.isNotEmpty(cash.getStatus()), "tpc.status", cash.getStatus());

        ((QueryWrapper<Cash>) queryWrapper).eq(StringUtil.isNotEmpty(cash.getPhone()), "ui.phone", cash.getPhone());

        ((QueryWrapper<Cash>) queryWrapper).eq(StringUtil.isNotEmpty(cash.getId()), "tpc.id", cash.getId());

        ((QueryWrapper<Cash>) queryWrapper).eq(StringUtil.isNotEmpty(cash.getUserId()), "tpc.userId", cash.getUserId());

        ((QueryWrapper<Cash>) queryWrapper).ge(StringUtil.isNotEmpty(cash.getBeginTime()), "tpc.createDt", cash.getBeginTime());

        ((QueryWrapper<Cash>) queryWrapper).le(StringUtil.isNotEmpty(cash.getEndTime()), "tpc.createDt", cash.getEndTime());

        final E result = (E) baseMapper.queryCashPage2(page, queryWrapper);

        List<Long> userIdList = new ArrayList<>();
        List<String> merchantCodeList = new ArrayList<>();
        for (Cash record : result.getRecords()) {
            userIdList.add(record.getUserId());
            merchantCodeList.add(record.getMerchantCode());
        }

        final List<Fans> fansList = fansMapper.selectGroupData(merchantCodeList);
        final List<MerchantProfit> merchantProfitList = mpMapper.selectGroupMercProfit(userIdList);

        for (Cash record : result.getRecords()) {
            final Iterator<Fans> fansIterator = fansList.iterator();

            while (fansIterator.hasNext()) {
                final Fans next = fansIterator.next();
                if (next.getLastMerchantCode().equals(record.getMerchantCode())) {
                    record.setTotalShareMoney(new BigDecimal(next.getShareMoney()));
                    fansIterator.remove();
                    break;
                }
            }

            final Iterator<MerchantProfit> profitIterator = merchantProfitList.iterator();
            while (profitIterator.hasNext()) {
                final MerchantProfit next = profitIterator.next();
                if (next.getUserId().equals(record.getUserId())) {
                    record.setTotalProfit(BigDecimal.valueOf(next.getPrice()));
                    profitIterator.remove();
                    break;
                }
            }
        }

        return result;
    }

    @Override
    public List<Cash> queryCashPage(Map<String, Object> map) {
        return baseMapper.queryCashPage(map);
    }

    @Override
    public Integer queryCashPageCount(Map<String, Object> map) {
        return baseMapper.queryCashPageCount(map);
    }

    @Override
    public Double sumFansSuccessCash(Map<String, Object> map) {
        Double aDouble = baseMapper.sumFansSuccessCash(map);
        return aDouble == null ? new Double(0) : aDouble;
    }

    @Override
    public Double sumFansAlreadyCash(Map<String, Object> map) {
        Double aDouble = baseMapper.sumFansAreadlyCash(map);
        return aDouble == null ? new Double(0) : aDouble;
    }

    @Override
    public Double sumMerchantSuccessCash(Long userId) {
        Double aDouble = baseMapper.sumMerChantSuccessCash(userId);
        return aDouble == null ? new Double(0) : aDouble;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void passAndRemit(Cash cash) {
        String remark = cash.getRemark();
        cash = baseMapper.selectLockById(cash.getId());
        if (cash.getStatus() == 1) {
            throw new MsgException("当前打款记录已被处理");
        }

        cash.setStatus(1);

        // String token = request.getHeader("token");
        // cash.setUpdator(JwtUtils.get("userId", token).toString());
        cash.setUpdateDt(new Date());
        updateById(cash);

        if (!StringUtils.isEmpty(remark)) {
            QueryWrapper<CommonRemark> qWrapper = new QueryWrapper<CommonRemark>()
                    .eq("userId", cash.getUserId())
                    .eq("code", "CASH");
            remarkService.remove(qWrapper);
            CommonRemark existData = new CommonRemark();
            existData.setUserId(cash.getUserId().intValue());
            existData.setCode("CASH");
            existData.setRemark(remark);
            remarkService.saveOrUpdate(existData);
        }

        String accountName = cash.getAccountName();
        String accountNo = cash.getAccountNo();
        if (StringUtils.isEmpty(accountName)) {
            LambdaQueryWrapper<CashAccount> qWrapper2 = new LambdaQueryWrapper<CashAccount>()
                    .eq(CashAccount::getUserId, cash.getUserId().intValue());
            CashAccount one = cashAccountService.getOne(qWrapper2);

            if (one == null) {
                throw new MsgException("缺少打款账号");
            } else {
                accountName = one.getAccountName();
                accountNo = one.getAccountNo();

                cash.setAccountNo(accountNo);
                cash.setAccountName(accountName);
                updateById(cash);
            }
        }

        alipayService.remit(accountNo, accountName, cash.getVirRealCashAmt().toString());
        // 发送分润打款通知
        generalPushUtil.sendAllPlatByAlias(Collections.singletonList(cash.getUserId() + ""), "收银呗分润到账通知", "您的分润已结算至支付宝，快去查看哦！", "1");
    }

    @Override
    public void batchPassAndRemit(List<String> idList) {
        // 获取要操作的提现记录
        LambdaQueryWrapper<Cash> qWrapper1 = new LambdaQueryWrapper<Cash>()
                .in(Cash::getId, idList);
        List<Cash> cashList = list(qWrapper1);

        // 获取所有要操作的提现记录的提现账号信息
        List<String> noAccountUserIdList = new ArrayList<String>();
        for (Cash cash : cashList) {
            if (StringUtils.isEmpty(cash.getAccountName())) {
                noAccountUserIdList.add(cash.getUserId() + "");
            }
        }

        if (!noAccountUserIdList.isEmpty()) {
            LambdaQueryWrapper<CashAccount> qWrapper2 = new LambdaQueryWrapper<CashAccount>()
                    .in(CashAccount::getUserId, noAccountUserIdList);
            List<CashAccount> cashAccountList = cashAccountService.list(qWrapper2);

            for (Cash cash : cashList) {
                if (cash.getAccountName() != null) {
                    continue;
                }

                for (CashAccount cashAccount : cashAccountList) {
                    if (cashAccount.getUserId().equals(cash.getUserId().intValue())) {
                        cash.setAccountName(cashAccount.getAccountName());
                        cash.setAccountNo(cashAccount.getAccountNo());
                        updateById(cash);
                    }
                }
            }

            if (cashAccountList.size() != noAccountUserIdList.size()) {
                throw new MsgException("存在没有提供提现账户的记录");
            }
        }

        for (Cash cash : cashList) {
            if (cash.getStatus() == 1) {
                continue;
            }

            self.passAndRemit(cash);
        }
    }

    /**
     * @description:统计提现信息记录
     * @date: 2021/10/15 16:39
     * @param params:
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    @Override
    public Map<String, Object> getCashCountData(Map<String, Object> params) {
        return baseMapper.getCashCountData(params);
    }
}

