package com.github.wxiaoqi.security.admin.biz;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.wxiaoqi.security.admin.dto.WalletCathSumDto;
import com.github.wxiaoqi.security.admin.dto.WalletFindDTO;
import com.github.wxiaoqi.security.admin.dto.WalletListDTO;
import com.github.wxiaoqi.security.admin.entity.*;
import com.github.wxiaoqi.security.admin.mapper.MyWalletMapper;
import com.github.wxiaoqi.security.admin.rpc.service.AppPermissionService;
import com.github.wxiaoqi.security.admin.vo.AppletWalletVo;
import com.github.wxiaoqi.security.admin.vo.ApplyCathVo;
import com.github.wxiaoqi.security.admin.vo.WalletPageVo;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.constant.UserConstant;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.app.entity.vo.WithDrawRuleVo;
import com.xxfc.platform.app.feign.ConfigFeign;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author libin
 * @version 1.0
 * @description
 * @data 2019/7/12 9:18
 */
@Transactional
@Service
@Slf4j
public class MyWalletBiz extends BaseBiz<MyWalletMapper, MyWallet> {

       @Autowired
       private MyWalletDetailBiz myWalletDetailBiz;

       @Autowired
       private MyWalletCathBiz  myWalletCathBiz;

       @Autowired
       private AppPermissionService permissionService;

        @Autowired
        private RedisTemplate userRedisTemplate;

        @Autowired
        private ConfigFeign configFeign;

        @Autowired
        private AppUserAlipayBiz alipayBiz;

        @Autowired
        private AppUserLoginBiz appUserLoginBiz;


        private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);


    public AppletWalletVo findMyWallet(Integer userId) {

        AppletWalletVo appletWalletVo = new AppletWalletVo();

        Example example = new Example(MyWallet.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId", userId);
        List<MyWallet> wallets = mapper.selectByExample(example);

        MyWallet myWallet = wallets.get(0);
        appletWalletVo.setBalance(myWallet.getBalance()==null?new BigDecimal(0):myWallet.getBalance());
        appletWalletVo.setTodayAmount(myWallet.getTodayAmount()==null?new BigDecimal(0):myWallet.getTodayAmount());
        appletWalletVo.setTotalAmount(myWallet.getTotalAmount()==null?new BigDecimal(0):myWallet.getTotalAmount());
        appletWalletVo.setUnbooked(myWallet.getUnbooked()==null?new BigDecimal(0):myWallet.getUnbooked());
        appletWalletVo.setUserId(myWallet.getUserId());
        return appletWalletVo;
    }

    public PageDataVO<WalletPageVo> listWalletWithPage(WalletFindDTO walletFindDTO) {

         PageDataVO<WalletPageVo> walletPageVo = new PageDataVO<>();
        PageDataVO<WalletListDTO> walletPage = PageDataVO.pageInfo(walletFindDTO.getPage(), walletFindDTO.getLimit(), () -> mapper.selectByPhoneOrUserName(walletFindDTO.getPhone(), walletFindDTO.getUsername()));
        List<WalletListDTO> wallets = walletPage.getData();
        if(CollectionUtils.isEmpty(wallets)){
            return walletPageVo;
        }

        List<Integer> userIds = wallets.stream().map(WalletListDTO::getUserId).collect(Collectors.toList());
        Map<Integer, BigDecimal> userIdAndTotalConsumptionMap = myWalletDetailBiz.finduserIdAndPersonalTotalConsumptionMapByUserIds(userIds);
        Map<Integer,BigDecimal> userIdAndWithdrawalingMap = myWalletCathBiz.findUserIdAndWithdrawalingMapByUserIds(userIds);

        List<WalletPageVo> walletPageVos = new ArrayList<>();
        WalletPageVo walletpg ;
        for (WalletListDTO wallet : wallets) {
            walletpg = new WalletPageVo();
            BeanUtils.copyProperties(wallet,walletpg);
            walletpg.setUsername(StringUtils.isEmpty(wallet.getRealname())?wallet.getNickname():wallet.getRealname());
            walletpg.setPhone(wallet.getUsername());

            BigDecimal totalConsumpution =  userIdAndTotalConsumptionMap==null?new BigDecimal(0):userIdAndTotalConsumptionMap.get(wallet.getUserId())==null?new BigDecimal(0):userIdAndTotalConsumptionMap.get(wallet.getUserId());
            BigDecimal withDrawaling  = userIdAndWithdrawalingMap==null?new BigDecimal(0):userIdAndWithdrawalingMap.get(wallet.getUserId())==null?new BigDecimal(0):userIdAndWithdrawalingMap.get(wallet.getUserId());
            walletpg.setWithdrawaling(withDrawaling);
            walletpg.setWithdrawals(walletpg.getWithdrawals()==null?new BigDecimal(0):walletpg.getWithdrawals());
            walletpg.setUnbooked(walletpg.getUnbooked()==null?new BigDecimal(0):walletpg.getUnbooked());
            walletpg.setTotalAmount(walletpg.getTodayAmount()==null?new BigDecimal(0):walletpg.getTotalAmount());
            walletpg.setTotalConsumption(totalConsumpution);
            walletPageVos.add(walletpg);
        }



        walletPageVos.sort(Comparator.comparing(WalletPageVo::getTotalAmount).reversed());
        walletPageVo.setPageNum(walletFindDTO.getPage());
        walletPageVo.setPageSize(walletFindDTO.getLimit());
        walletPageVo.setTotalCount(walletPage.getTotalCount());
        walletPageVo.setTotalPage(walletPage.getTotalPage());
        walletPageVo.setData(walletPageVos);
        return walletPageVo;
    }

    //检查手机号码是否正确
    public ObjectRestResponse checkCode(String phone,String mobilecod){
        boolean flag=false;
        String key=permissionService.checkCodeByUsername(phone,mobilecod);
        if (StringUtils.isNotBlank(key)){
            flag=true;
        }
        return ObjectRestResponse.succ(flag);
    }

    //设置密码type 1-设置密码；2-修改密码
    public ObjectRestResponse setPwd(Integer userId,String phone,String mobilecod,String password,Integer type){
        if (StringUtils.isBlank(phone)||StringUtils.isBlank(mobilecod)||StringUtils.isBlank(password)){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数为空");
        }
        String key=permissionService.checkCodeByUsername(phone,mobilecod);
        if (StringUtils.isBlank(key)){
            return ObjectRestResponse.createFailedResult(ResultCode.NOTEXIST_CODE, "验证码错误");
        }
        userRedisTemplate.delete(key);
        MyWallet myWallet=new MyWallet();
        myWallet.setUserId(userId);
        myWallet = selectOne(myWallet);
        if (myWallet==null){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "钱包不存在");
        }
        if(type==1&&StringUtils.isNotBlank(myWallet.getPayPassword())){
            return ObjectRestResponse.createFailedResult(ResultCode.EXIST_CODE, "密码已存在");
        }
        password=new BCryptPasswordEncoder(UserConstant.PW_ENCORDER_SALT).encode(password);
        myWallet.setPayPassword(password);
        updateSelectiveById(myWallet);
        return  ObjectRestResponse.succ();
    }

    //检查用户是否设置过密码
    public ObjectRestResponse checkSetPwd(Integer userId){
        MyWallet myWallet=new MyWallet();
        myWallet.setUserId(userId);
        myWallet = selectOne(myWallet);
        if (myWallet==null){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "钱包不存在");
        }
        boolean flag=false;
        if(StringUtils.isNotBlank(myWallet.getPayPassword())){
            flag=true;
        }
        return  ObjectRestResponse.succ(flag);
    }

    //检查提成下一步操作
    public ObjectRestResponse checkAmount(Integer userId,BigDecimal amount,String password){
        if (amount.compareTo(BigDecimal.ZERO)<1){
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现金额不能小于0");
        }
        MyWallet myWallet=new MyWallet();
        myWallet.setUserId(userId);
        myWallet = selectOne(myWallet);
        if (myWallet==null){
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "钱包不存在");
        }
        if (amount.compareTo(myWallet.getBalance())>0){
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现金额不能大于钱包金额");
        }
        if (StringUtils.isNotBlank(password)&&!encoder.matches(password,myWallet.getPayPassword())){
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "支付密码错误");
        }
        WithDrawRuleVo ruleVo=configFeign.getWithDrawRule();
        BigDecimal proceduReates=BigDecimal.ZERO;
        WalletCathSumDto sumDto=new WalletCathSumDto();
        if (ruleVo!=null){
             proceduReates=ruleVo.getProceduReates();
            //提现次数
            Integer number=1;
            //最小金额
            BigDecimal mimAmount=ruleVo.getMinAmount();
            if (mimAmount.compareTo(BigDecimal.ZERO)>0&&amount.compareTo(mimAmount)<0){
                return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现金额不能小于"+mimAmount+"元");
            }
            //日额度
            BigDecimal amountOfDay=ruleVo.getAmountOfDay();
            //每日次数
            Integer  maxNumberOfDay=ruleVo.getMaxNumberOfDay()==null?0:ruleVo.getMaxNumberOfDay();
            //查询当日次数和金额
             sumDto=myWalletCathBiz.sumCathAmount(userId,1);
            BigDecimal ramount=amount.add(sumDto.getSumAmount());
            if (amountOfDay.compareTo(BigDecimal.ZERO)>0&&ramount.compareTo(amountOfDay)>0){
                return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现金额超过日额度"+amountOfDay+"元");
            }
            number+=sumDto.getNumber();
            if (maxNumberOfDay>0&&number>maxNumberOfDay){
                return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现当日次数超过"+maxNumberOfDay+"次");
            }
            number=1;
            //月额度
            BigDecimal  amountOfMonth=ruleVo.getAmountOfMonth();
            //月次数
            Integer maxNumberOfMonth=ruleVo.getMaxNumberOfMonth();

            //查询当月次数和金额
             sumDto=myWalletCathBiz.sumCathAmount(userId,2);
             BigDecimal yamount=amount.add(sumDto.getSumAmount());
             if (amountOfMonth.compareTo(BigDecimal.ZERO)>0&&yamount.compareTo(amountOfMonth)>0){
                 return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现金额超过月额度"+amountOfMonth+"元");
            }
            number+=sumDto.getNumber();
            if (maxNumberOfMonth>0&&number>maxNumberOfMonth){
                return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现当月次数超过"+maxNumberOfMonth+"次");
            }

        }
        sumDto.setBalance(myWallet.getBalance());
        sumDto.setProceduReates(proceduReates);
        sumDto.setWalletId(myWallet.getId());
        sumDto.setVersion(myWallet.getVersion());
        return  ObjectRestResponse.succ(sumDto);
    }


    //返回提现规则
    public ObjectRestResponse getCathRule(){
        return  ObjectRestResponse.succ(configFeign.getWithDrawRule());
    }

    //提现申请
    public  ObjectRestResponse applyCath(ApplyCathVo applyCathVo){
        if (applyCathVo==null){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数不能为空");
        }
        Integer userId=applyCathVo.getUserId();
        BigDecimal amount=applyCathVo.getAmount();
        String password=applyCathVo.getPassword();
        String accountNumber=applyCathVo.getAccountNumber();
        Integer cathType=applyCathVo.getCathType()==null?1:applyCathVo.getCathType();
        if (StringUtils.isBlank(password)||amount.compareTo(BigDecimal.ZERO)<1){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数不能为空");
        }
        ObjectRestResponse restResponse=checkAmount(userId,amount,password);
        if (restResponse.getStatus()!=ResultCode.SUCCESS_CODE){
              return  restResponse;
        }
        String data=JSONObject.toJSONString(restResponse.getData());
        WalletCathSumDto sumDto=JSONUtil.toBean( data,WalletCathSumDto.class);
        if (sumDto==null){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数不能为空");
        }
        BigDecimal commission=amount.multiply(sumDto.getProceduReates()).divide(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
        BigDecimal balnece=sumDto.getBalance();
        //到账金额
        BigDecimal realAmount=amount;
        if ((realAmount.add(commission)).compareTo(balnece)>0){
            realAmount=balnece.subtract(commission);
        }
        log.info("-----提现申请-----proceduReates==="+sumDto.getProceduReates()+"----commission===="+commission+"---realAmount==="+realAmount);
        //添加账号
         alipayBiz.addAlipay(userId,accountNumber);
         MyWalletCath walletCath=new MyWalletCath();
         walletCath.setUserId(userId);
         walletCath.setBalance(balnece);
         walletCath.setCathType(cathType);
         walletCath.setAccountNumber(accountNumber);
         walletCath.setAmount(amount);
         walletCath.setCommission(commission);
         walletCath.setRealAmount(realAmount);
         myWalletCathBiz.insertSelective(walletCath);
         //提现金额
        BigDecimal withdrawals=realAmount.add(commission);
        balnece=balnece.subtract(withdrawals).setScale(2, RoundingMode.HALF_UP);
        log.info("------钱包----withdrawals==="+withdrawals+"----balnece===="+balnece);
         MyWallet  myWallet=new MyWallet();
         myWallet.setId(sumDto.getWalletId());
         myWallet.setUserId(userId);
         myWallet.setBalance(balnece);
         myWallet.setWithdrawals(withdrawals);
         myWallet.setVersion(sumDto.getVersion());
         mapper.updMyWater(myWallet);
         return  ObjectRestResponse.succ(walletCath.getId());
    }


    //提现审核
    public  ObjectRestResponse  verifyCath(Integer cathId,String cono,String reason,Integer status){
        if ((status==1&&StringUtils.isBlank(cono))||(status==2&&StringUtils.isBlank(reason))||cathId==null||cathId==0){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数不能为空");
        }
        MyWalletCath cath=myWalletCathBiz.selectById(cathId);
        if (cath==null){
            return ObjectRestResponse.createFailedResult(ResultCode.NOTEXIST_CODE, "提现记录不存在");
        }
        cath.setStauts(status);
        cath.setCono(cono);
        cath.setReason(reason);
        cath.setFinishTime(System.currentTimeMillis());
        int num=myWalletCathBiz.updateSelectiveByIdRe(cath);
        if (num>0){
            Integer userId=cath.getUserId();
            MyWallet wallet=new MyWallet();
            wallet.setUserId(userId);
            wallet=selectOne(wallet);
            if (wallet!=null){
                //当时钱包的余额
                BigDecimal balance=cath.getBalance();
                BigDecimal realAmount=cath.getRealAmount();
                BigDecimal commission=cath.getCommission();
                if (status==1){
                    MyWalletDetail detail=new MyWalletDetail();
                    detail.setUserId(userId);
                    detail.setItype(1);
                    detail.setCono(cathId);
                    detail.setBalance(balance);
                    detail.setAmount(realAmount);
                    detail.setSource(10);
                    myWalletDetailBiz.insertSelective(detail);
                    detail.setId(null);
                    detail.setSource(13);
                    balance=balance.subtract(realAmount).setScale(2, RoundingMode.HALF_UP);
                    detail.setBalance(balance);
                    detail.setAmount(commission);
                    myWalletDetailBiz.insertSelective(detail);
                }else {
                    BigDecimal amount=realAmount.add(commission);
                    balance=wallet.getBalance().add(amount);
                    BigDecimal withdrawals=wallet.getWithdrawals().subtract(amount);
                    wallet.setBalance(balance);
                    wallet.setWithdrawals(withdrawals);
                    mapper.updMyWater(wallet);
                }

            }
        }
        return  ObjectRestResponse.succ();
  }

    public void deleteByUserIds(Collection<Integer> userIds) {
        Example example =new Example(MyWallet.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("userId",userIds);
        mapper.deleteByExample(example);
    }
}
