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


import cn.hutool.core.lang.Snowflake;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.wxiaoqi.security.admin.constant.WithDrawStatusEnum;
import com.github.wxiaoqi.security.admin.constant.enumerate.CompanyWalletSourceEnum;
import com.github.wxiaoqi.security.admin.dto.CompanyAccountDTO;
import com.github.wxiaoqi.security.admin.dto.CompanyWalletPwdDTO;
import com.github.wxiaoqi.security.admin.dto.WalletCathDTO;
import com.github.wxiaoqi.security.admin.dto.WalletCathSumDto;
import com.github.wxiaoqi.security.admin.entity.*;
import com.github.wxiaoqi.security.admin.mapper.CompanyWalletCathMapper;
import com.github.wxiaoqi.security.admin.rpc.service.AppPermissionService;
import com.github.wxiaoqi.security.admin.vo.ApplyCathVo;
import com.github.wxiaoqi.security.admin.vo.CompanyWalletCathVo;
import com.github.wxiaoqi.security.admin.vo.CompanyWalletDetailVo;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.config.rabbit.RabbitConstant;
import com.github.wxiaoqi.security.common.constant.UserConstant;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.ClientUtil;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.app.entity.Cofig;
import com.xxfc.platform.app.entity.vo.WithDrawRuleVo;
import com.xxfc.platform.app.enumconstant.WithDrawWayEnum;
import com.xxfc.platform.app.feign.ConfigFeign;
import com.xxfc.platform.universal.vo.FundPayVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
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.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;


@Service
@Slf4j
public class CompanyWalletCathBiz extends BaseBiz<CompanyWalletCathMapper, CompanyWalletCath> implements InitializingBean {

    @Autowired
    CompanyWalletBiz companyWalletBiz;


    @Autowired
    CompanyWalletDetailBiz walletDetailBiz;


    @Autowired
    BranchCompanyBiz branchCompanyBiz;


    private Snowflake snowflake;

    private DateTimeFormatter dateTimeFormatter;

    @Autowired
    private AppPermissionService permissionService;

    @Autowired
    private RedisTemplate userRedisTemplate;

    @Autowired
    ConfigFeign configFeign;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    CompanyInfoBiz companyInfoBiz;

    @Autowired
    BaseOrderRevenueBiz revenueBiz;


    private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);




    public List<CompanyWalletCathVo> getList(WalletCathDTO walletCathDTO){
        return  mapper.selectList(walletCathDTO);
    }


    public PageDataVO<CompanyWalletDetailVo> selectList(WalletCathDTO walletCathDTO) {
        return PageDataVO.pageInfo(walletCathDTO.getPage(), walletCathDTO.getLimit(), () -> getList(walletCathDTO));
    }


    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public ObjectRestResponse applyCath(ApplyCathVo applyCathVo){
        Integer companyId = applyCathVo.getUserId() == null ? 0 : applyCathVo.getUserId();
        Integer revenueId = applyCathVo.getRevenueId() == null ? 0 : applyCathVo.getRevenueId();
        if (revenueId == 0 || companyId == 0) {
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数不能为空");
        }
        JSONObject jsonObject = checkSetPwdOrAccount(companyId);
        boolean flag = jsonObject.getBoolean("result");
        if (!flag){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "密码或银行卡未设置");
        }
        applyCathVo.setAccountNumber(jsonObject.getString("accountNumber"));
        applyCathVo.setAccountName(jsonObject.getString("accountName"));
        applyCathVo.setBank(jsonObject.getString("bank"));
        return  apply(applyCathVo);
    }


    //提现申请
    public ObjectRestResponse apply(ApplyCathVo applyCathVo) {
        Integer companyId = applyCathVo.getUserId();
        String password = applyCathVo.getPassword();
        String accountNumber = applyCathVo.getAccountNumber();
        Integer cathType = applyCathVo.getCathType() == null ? 2 : applyCathVo.getCathType();
        Integer revenueId = applyCathVo.getRevenueId() == null ? 0 : applyCathVo.getRevenueId();
        BaseOrderRevenue baseOrderRevenue = revenueBiz.selectById(revenueId);
        if (baseOrderRevenue == null ){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "营收记录不存在");
        }
        if (!companyId.equals(baseOrderRevenue.getCompanyId())){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "无权限操作");
        }
        if (baseOrderRevenue.getStatus() != 1 && baseOrderRevenue.getStatus() != 3){
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "订单无法提现");
        }
        BigDecimal amount = baseOrderRevenue.getAmount();
        if (StringUtils.isBlank(password) || amount.compareTo(BigDecimal.ZERO) < 1) {
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数不能为空");
        }
        ObjectRestResponse restResponse = checkAmount(companyId, 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, "参数不能为空");
        }

        CompanyWalletCath walletCath = new CompanyWalletCath();
        Integer withdrawWay = sumDto.getWithdrawWay() == null ? 0 : sumDto.getWithdrawWay();

        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);
        }
        //提现单号
        String orderNo = snowflake.nextIdStr();
        orderNo = String.format("%s%s", dateTimeFormatter.format(LocalDate.now()), orderNo);
        log.info("-----提现申请-----proceduReates===" + sumDto.getProceduReates() + "----commission====" + commission + "---realAmount===" + realAmount);
        walletCath.setCrtTime(Instant.now().toEpochMilli());
        walletCath.setCathNo(orderNo);
        walletCath.setStauts(WithDrawStatusEnum.AUDIT.getCode());
        walletCath.setCompanyId(companyId);
        walletCath.setBalance(balnece);
        walletCath.setCathType(cathType);
        walletCath.setAccountName(applyCathVo.getAccountName());
        walletCath.setAccountNumber(accountNumber);
        walletCath.setAmount(amount);
        //手续费
        walletCath.setCommission(commission);
        walletCath.setRealAmount(realAmount);
        walletCath.setWithdrawWay(withdrawWay);
        walletCath.setOrderNo(baseOrderRevenue.getOrderNo());
        walletCath.setRevenueId(applyCathVo.getRevenueId());
        insertSelective(walletCath);
        //提现金额
        BigDecimal withdrawals = realAmount.add(commission);
        balnece = balnece.subtract(withdrawals).setScale(2, RoundingMode.HALF_UP);
        log.info("------钱包----withdrawals===" + withdrawals + "----balnece====" + balnece);
        CompanyWallet companyWallet = new CompanyWallet();
        companyWallet.setId(sumDto.getWalletId());
        companyWallet.setCompanyId(companyId);
        companyWallet.setBalance(balnece);
        companyWallet.setWithdrawals(withdrawals);
        companyWallet.setVersion(sumDto.getVersion());
        companyWalletBiz.updCompanyWallet(companyWallet);
        //线上自动提现
        if (WithDrawWayEnum.WITHDRAW_ONLINE_WAY.getCode() == withdrawWay) {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String host = StringUtils.defaultIfBlank(request.getHeader("userHost"), ClientUtil.getClientIp(request));
            FundPayVo fundPayVo = FundPayVo.builder()
                    .amount(applyCathVo.getCathType() == 0 ? String.format("%.0f",realAmount.multiply(new BigDecimal(100)).doubleValue()) : String.format("%.2f", realAmount.doubleValue()))
                    .orderNo(orderNo)
                    .payeeAccount(applyCathVo.getAccountNumber())
                    .payerShowName("广东升云信息科技有限公司")
                    .remark("提现转账")
                    .type(applyCathVo.getCathType())
                    .creatIp(host)
                    .build();
            //发送提现申请
            sendPayMessage(fundPayVo);
        }
        BaseOrderRevenue baseOrderRevenue1 = new BaseOrderRevenue();
        baseOrderRevenue1.setId(baseOrderRevenue.getId());
        baseOrderRevenue1.setStatus(4);
        revenueBiz.updateSelectiveById(baseOrderRevenue1);
        return ObjectRestResponse.succ(walletCath.getId());
    }



    private void sendPayMessage(FundPayVo fundPayVo) {
        String json = JSON.toJSONString(fundPayVo);
        Message message = MessageBuilder.withBody(json.getBytes())
                .setContentType(MessageProperties.CONTENT_TYPE_JSON).setContentEncoding("utf-8")
                .setMessageId(UUID.randomUUID() + "")
                .setHeader("x-delay", 2000).build();
        rabbitTemplate.convertAndSend(RabbitConstant.ADMIN_TOPIC, RabbitConstant.KEY_WALLET_WITH_DRAW, message);
    }


    public void withDrawProcess(CompanyWalletCath companyWalletCath) {
        CompanyWalletCath companyWalletCath1 = selectById(companyWalletCath.getId());
        if (companyWalletCath1 == null) {
            throw new BaseException("提现记录不存在",ResultCode.FAILED_CODE);
        }
        if (companyWalletCath1.getStauts().equals(WithDrawStatusEnum.SUCCESS.getCode()) || companyWalletCath1.getStauts().equals(WithDrawStatusEnum.FAIL.getCode())) {
            throw new BaseException("已审核",ResultCode.FAILED_CODE);
        }
        CompanyWallet companyWallet=companyWalletBiz.selectById(companyWalletCath1.getCompanyId());
        if (companyWallet == null) {
            throw new BaseException("钱包不存在", ResultCode.FAILED_CODE);
        }
        BaseOrderRevenue baseOrderRevenue = revenueBiz.selectById(companyWalletCath1.getRevenueId());
        if (baseOrderRevenue == null) {
            throw new BaseException("营收记录不存在", ResultCode.FAILED_CODE);
        }
        BaseOrderRevenue baseOrderRevenue1 = new BaseOrderRevenue();
        baseOrderRevenue1.setId(baseOrderRevenue.getId());
        baseOrderRevenue1.setReson(companyWalletCath.getReason());
        if (companyWalletCath.getStauts() == WithDrawStatusEnum.SUCCESS.getCode()) {
            CompanyWalletDetail detail = new CompanyWalletDetail();
            detail.setCono(companyWalletCath1.getCathNo());
            detail.setSAmount(companyWalletCath1.getBalance());
            detail.setAmount(companyWalletCath1.getAmount());
            detail.setItype(revenueBiz.getType(baseOrderRevenue.getType()));
            detail.setSource(CompanyWalletSourceEnum.CATH.getCode());
            //设置提现单号
            detail.setCompanyId(companyWalletCath1.getCompanyId());
            walletDetailBiz.insertSelective(detail);
            companyWalletCath.setWalletDetailId(detail.getId());
            baseOrderRevenue1.setStatus(2);
        }else {
            //更新钱包
            BigDecimal withdrawals = companyWallet.getWithdrawals().subtract(companyWalletCath1.getAmount()).setScale(2, RoundingMode.HALF_UP);
            BigDecimal balance = companyWallet.getBalance().add(companyWalletCath1.getAmount()).setScale(2, RoundingMode.HALF_UP);
            CompanyWallet companyWallet1 =new CompanyWallet();
            companyWallet1.setBalance(balance);
            companyWallet1.setWithdrawals(withdrawals);
            companyWallet1.setCompanyId(companyWallet.getCompanyId());
            companyWalletBiz.updateSelectiveById(companyWallet1);
            baseOrderRevenue1.setStatus(3);
        }
        companyWalletCath.setFinishTime(Instant.now().toEpochMilli());
        updateSelectiveById(companyWalletCath);
        revenueBiz.updateSelectiveById(baseOrderRevenue1);

    }


    //检查手机号码是否正确
    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);
    }


    //发送验证码
    public JSONObject sendSMS(String phone) {
        return  permissionService.sendSMS(phone,4,null);
    }


    //设置密码type 1-设置密码；2-修改密码
    public ObjectRestResponse setPwd(CompanyWalletPwdDTO companyWalletPwdDTO) {
        String phone = companyWalletPwdDTO.getPhone();
        String mobilecod = companyWalletPwdDTO.getMobilecod();
        String password = companyWalletPwdDTO.getPassword();
        Integer type = companyWalletPwdDTO.getType() == null ? 0 : companyWalletPwdDTO.getType();
        Integer companyId = companyWalletPwdDTO.getCompanyId() == null ? 0 : companyWalletPwdDTO.getCompanyId();
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(mobilecod) || StringUtils.isBlank(password) || companyId == 0 || type == 0) {
            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);
        CompanyWallet  companyWallet = companyWalletBiz.selectById(companyId);
        if (companyWallet == null) {
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "钱包不存在");
        }
        if (type == 1 && StringUtils.isNotBlank(companyWallet.getPayPassword())) {
            return ObjectRestResponse.createFailedResult(ResultCode.EXIST_CODE, "密码已存在");
        }
        password = new BCryptPasswordEncoder(UserConstant.PW_ENCORDER_SALT).encode(password);
        companyWallet.setPayPassword(password);
        companyWalletBiz.updateSelectiveById(companyWallet);
        return ObjectRestResponse.succ();
    }


    //检查用户是否设置过密码
    public JSONObject checkSetPwdOrAccount(Integer companyId) {
        CompanyInfo companyInfo = companyInfoBiz.getInfoByCompanyId(companyId);
        if (companyInfo == null ){
            throw  new BaseException("商家不存在",ResultCode.NULL_CODE);
        }
        CompanyWallet  companyWallet = companyWalletBiz.selectById(companyId);
        if (companyWallet == null) {
            throw  new BaseException("钱包不存在",ResultCode.NULL_CODE);
        }
        JSONObject result = new JSONObject();
        result.put("result",false);
        Integer type = 0;
        result.put("accountNumber","");
        result.put("accountName","");
        result.put("bank","");
        if (StringUtils.isBlank(companyInfo.getBankAccount()) || StringUtils.isBlank(companyInfo.getBankName())){
            if (StringUtils.isBlank(companyWallet.getPayPassword())) {
                type=3;
            }else {
                type=2;
            }
        }else {
            if (StringUtils.isBlank(companyWallet.getPayPassword())) {
                type=1;
            }else {
                result.put("result",true);
                result.put("accountNumber",companyInfo.getBankAccount());
                result.put("accountName",companyInfo.getBankName());
                result.put("bank",companyInfo.getBank());
            }
        }
        result.put("type",type);
        return result;
    }

    //检查提成下一步操作
    public ObjectRestResponse checkAmount(Integer companyId, BigDecimal amount, String password) {
        if (amount.compareTo(BigDecimal.ZERO) < 1) {
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现金额不能小于0");
        }
        CompanyWallet companyWallet = companyWalletBiz.selectById(companyId);
        if (companyWallet == null) {
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "钱包不存在");
        }
        if (amount.compareTo(companyWallet.getBalance()) > 0) {
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "提现金额不能大于钱包金额");
        }
        if (StringUtils.isNotBlank(password) && !encoder.matches(password, companyWallet.getPayPassword())) {
            return ObjectRestResponse.createFailedResult(ResultCode.FAILED_CODE, "支付密码错误");
        }
        WithDrawRuleVo ruleVo = 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 = mapper.sumCathAmount(companyId, 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 = mapper.sumCathAmount(companyId, 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(companyWallet.getBalance());
        sumDto.setProceduReates(proceduReates);
        sumDto.setWalletId(companyWallet.getId());
        sumDto.setVersion(companyWallet.getVersion());
        sumDto.setWithdrawWay(sumDto.getWithdrawWay());
        return ObjectRestResponse.succ(sumDto);
    }



    //获取提现规则
    public WithDrawRuleVo getWithDrawRule(){
        try {
            List<Cofig> list=configFeign.getAllByType(ConfigFeign.TYPE_COMPANY_CATH+"").getData();
            if (list!=null && list.size()>0){
                String params=list.get(0).getParams();
                return  JSONUtil.toBean(params, WithDrawRuleVo.class);
            }
        }catch (Exception e){
            log.error(e.getMessage(), e);;
        }
        return  null;
    }



    @Override
    public void afterPropertiesSet() throws Exception {
        snowflake = new Snowflake(2, 2, false);
        dateTimeFormatter = DateTimeFormatter.ofPattern("YYYYMMdd");
    }


    public  void  updAccount(CompanyAccountDTO companyAccountDTO){
        CompanyInfo companyInfo = companyInfoBiz.getInfoByCompanyId(companyAccountDTO.getCompanyId());
        if (companyInfo == null ){
            throw  new BaseException("商家不存在",ResultCode.NULL_CODE);
        }
        CompanyInfo companyInfo1 = new CompanyInfo();
        BeanUtils.copyProperties(companyAccountDTO,companyInfo1);
        companyInfo1.setId(companyInfo.getId());
        companyInfoBiz.saveOrUpd(companyInfo1);
    }












}
