package com.jxy.order.service.impl;

import com.jxy.common.core.Result.R;
import com.jxy.common.core.constant.Constants;
import com.jxy.common.core.constant.SecurityConstants;
import com.jxy.common.core.exception.ServiceException;
import com.jxy.common.core.text.DoubleCalculate;
import com.jxy.common.core.utils.DateUtils;
import com.jxy.common.core.utils.StringUtils;
import com.jxy.common.core.web.Result.AjaxResult;
import com.jxy.common.security.service.TokenService;
import com.jxy.common.security.utils.SecurityUtils;
import com.jxy.order.dto.ConsumeDto;
import com.jxy.order.dto.ReduceResultDto;
import com.jxy.order.dto.SysRoleDto;
import com.jxy.order.dto.UserAccountDto;
import com.jxy.order.entity.*;
import com.jxy.order.enums.BasePrice;
import com.jxy.order.enums.ConsumeStatus;
import com.jxy.order.enums.OrderStatus;
import com.jxy.order.enums.UserLevel;
import com.jxy.order.mapper.ConsumeMapper;
import com.jxy.order.mapper.OrderMapper;
import com.jxy.order.service.ConsumeService;
import com.jxy.order.service.OrderService;
import com.jxy.order.vo.LevelUpVo;
import com.jxy.order.vo.StatusPageVo;
import com.jxy.system.api.RemoteUserService;
import com.jxy.system.api.entity.SysRole;
import com.jxy.system.api.entity.SysUserLeveDate;
import com.jxy.system.api.model.LoginUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Date 2023/5/31 15:22
 * @Author 杜懿
 */
@Service
public class ConsumeServiceImpl implements ConsumeService {

    @Autowired
    private RemoteUserService remoteUserService;

    @Autowired
    private ConsumeMapper consumeMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private OrderService orderService;


    @Override
    public AjaxResult getNeedFunding() {

        List<RecevingInfo> list = new ArrayList<>();

        RecevingInfo info1 = getInfoByRoleId(SecurityUtils.getLoginUser().getSysUser().getRoleId(),0);
        if(StringUtils.isNull(info1)){
            return AjaxResult.error("后台繁忙,拉取支付信息异常");
        }
        list.add(info1);

        RecevingInfo info2 = getInfoByRoleId(SecurityUtils.getLoginUser().getSysUser().getRoleId(),1);
        if(StringUtils.isNull(info1)){
            return AjaxResult.error("后台繁忙,拉取支付信息异常");
        }
        list.add(info2);

        RecevingInfo info3 = getInfoByRoleId(SecurityUtils.getLoginUser().getSysUser().getRoleId(),2);
        if(StringUtils.isNull(info1)){
            return AjaxResult.error("后台繁忙,拉取支付信息异常");
        }
        list.add(info3);

        return AjaxResult.success(list);
    }

    @Override
    //@GlobalT
    @Transactional
    public AjaxResult levelUp(LevelUpVo vo) {


        //判断用户是否有待处理订单 如有则取消当前订单
        int count = consumeMapper.checkOrderIfExistByUserId(SecurityUtils.getUserId());

        if(count > 0){
            return AjaxResult.error(802,"有订单待处理，无法再次提交新订单");
        }else{

        }

        RecevingInfo info = getInfoByRoleId(SecurityUtils.getLoginUser().getSysUser().getRoleId(),vo.getType());
        if (StringUtils.isNull(info)){

            //todo 放入队列中后台执行
            return AjaxResult.success();
        }


        //生成升级订单表数据 入库
        LevelUpOrder order = new LevelUpOrder();
        BeanUtils.copyProperties(vo,order);
        order.setUserId(SecurityUtils.getUserId());
        String level = UserLevel.getLevelByRoleId(SecurityUtils.getLoginUser().getSysUser().getRoleId());
        order.setAmountReceivable(info.getValue());
        if("".equals(level)){
            return AjaxResult.error("该功能仅对L2/L3/L4用户开放");
        }

        // 走到这里 用户角色基本确定为网站外来用户：注册用户、付费用户、VIP
        Long roleId = SecurityUtils.getLoginUser().getSysUser().getRoleId();

        //根据用户当前roleId和购买类型进行后续处理
        //roleId==4  type仅支持2 即 L4用户只能选择购买L4服务 oper设置为1续费
        //roleId==3  type为0或者1时代表续费会员 oper设置为1续费 type为2代表升级为L4 oper设置为0
        //roleId==2  type为0、1、2 均代表升级 oper设置为0

        int oper = 0;
        if(roleId == 4 && vo.getType() < 2){
            return AjaxResult.error("用户当前等级为L4,无需购买L4以下的服务");
        }

        if(roleId == 4){
            //VIP 说明是需要续费年度VIP(type=2)  后续需要执行续费操作
            System.out.println("续费年度vip，设置oper为1");
            oper = 1;
        }

        if(roleId == 3 && vo.getType() < 2){
            oper = 1;
        }

        if(vo.getType() == 2){
            order.setContent("购买年度L4用户服务");
            roleId = 4L;
        }else if(vo.getType() == 1){
            order.setContent("购买年度L3用户服务");
            roleId = 3L;
        }else {
            order.setContent("购买月度L3用户服务");
            roleId = 3L;
        }

        //扣款
        ReduceResultDto reduceResult = reduceBalance(SecurityUtils.getUserId(), BigDecimal.valueOf(info.getValue()));
        if(StringUtils.isNull(reduceResult)){
            order.setStatus(OrderStatus.PAY_FAIL.getCode());
            //记录失败的升级订单 标记风险用户
            if(!consumeMapper.insertConsume(order)) {
                return AjaxResult.error("服务器异常");
            }else {
                //标记风险用户

                return AjaxResult.error("余额不足,此次升级根据公式："+info.getFormula()+",应支付金额："+info.getValue());
            }
        }else {
            //扣款后：升级用户和生成订单
            System.out.println("已扣款 即将执行后续操作");
            SysUserLeveDate userLeveDate = new SysUserLeveDate();
            userLeveDate.setUserId(SecurityUtils.getUserId());
            userLeveDate.setRoleId(roleId);
            userLeveDate.setLevelType(vo.getType());
            userLeveDate.setOper(oper);

            Date date = new Date();
            userLeveDate.setStartTime(date);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            if(vo.getType() > 0){
                //年度会员/年度vip  会员有效期设置为一年
                calendar.add(Calendar.YEAR,1);
            }else {
                calendar.add(Calendar.MONTH,1);
            }
            userLeveDate.setExpireTime(calendar.getTime());

            //用户升级
            R<Boolean> booleanR = remoteUserService.userLevelup(userLeveDate, SecurityConstants.INNER);
            if(booleanR.getCode() == 200){
                //生成订单
                System.out.println("用户升级微服务调用成功");
                order.setStatus(OrderStatus.SUCCESS.getCode());
                //记录升级订单
                if(!consumeMapper.insertConsume(order)) {
                    return AjaxResult.error("系统异常，记录升级信息失败，请稍后再试");
                }else {
                    //修改余额表
                    UserBalance userBalance = reduceResult.getUb();
                    userBalance.setCoin(vo.getCoin());
                    userBalance.setChain("");
                    userBalance.setUserId(SecurityUtils.getUserId());
                    userBalance.setTxid("");
                    userBalance.setNotes(1);
                    userBalance.setMessage(order.getContent());
                    if(orderMapper.insertUserBalance(userBalance)){
                        //刷新token
                        System.out.println("用户邮箱："+SecurityUtils.getLoginUser().getSysUser().getEmail());
                        R<LoginUser> userResult = remoteUserService.getUserInfo(SecurityUtils.getLoginUser().getSysUser().getEmail(), SecurityConstants.INNER);

                        int times=0;
                        while (R.FAIL == userResult.getCode()){
                            if (times > 2){
                                break;
                            }
                            userResult = remoteUserService.getUserInfo(SecurityUtils.getLoginUser().getSysUser().getEmail(), SecurityConstants.INNER);
                            times++;
                        }

                        if (R.FAIL == userResult.getCode())
                        {
                            System.out.println(userResult);
                            return AjaxResult.error("后台繁忙，用户信息微服务调用失败,请稍后再试\n"+userResult.getMsg());
                        }

                        if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
                        {
                            return AjaxResult.error("后台繁忙，用户信息查询失败,请稍后再试");
                        }
                        System.out.println("查询到的用户信息："+userResult.getData());
                        Map<String, Object> token = tokenService.createToken(userResult.getData());
                        SysRole role = userResult.getData().getSysUser().getRoles().get(0);
                        SysRoleDto roleDto = new SysRoleDto();
                        roleDto.setLevelExpireDate(role.getLevelExpireDate());
                        roleDto.setRoleId(role.getRoleId());
                        roleDto.setRoleKey(role.getRoleKey());
                        roleDto.setRoleName(role.getRoleName());
                        if(role.getRoleId() == 3){
                            roleDto.setLevel("L3");
                            if(vo.getType() == 0){
                                roleDto.setRoleName("月度"+roleDto.getRoleName());
                            }else if(vo.getType() == 1){
                                roleDto.setRoleName("年度"+roleDto.getRoleName());
                            }
                        }else if(role.getRoleId() == 4){
                            roleDto.setLevel("L4");
                        }else {
                            roleDto.setLevel(roleDto.getRoleKey());
                        }
                        token.put("role", roleDto);

                        System.out.println("新token"+token);
                        if(StringUtils.isNotNull(token)){
                            if(StringUtils.isNotNull(token.get("access_token"))){
                                tokenService.delLoginUser(SecurityUtils.getToken());

                                return AjaxResult.success(token);
                            }
                        }
                        return AjaxResult.error("后台繁忙,请稍后再试");
                    }else {
                        //修改失败返回null
                        return AjaxResult.error("后台繁忙,请稍后再试");
                    }
                }
            }else {
                System.out.println("用户升级微服务调用失败");
                return AjaxResult.error("后台繁忙，调用升级微服务失败，请稍后再试");
            }

        }
    }

    @Override
    public List<ConsumeDto> privateConsume(StatusPageVo vo) {
        List<Consume> list = consumeMapper.getConsumeByUserId(SecurityUtils.getUserId(), vo.getStatus());
        List<ConsumeDto> returnList = list.stream().map(e -> {
            ConsumeDto dto = new ConsumeDto();
            BeanUtils.copyProperties(e,dto);
            dto.setStatus(ConsumeStatus.getStatusByCode(e.getState()));
            return dto;
        }).collect(Collectors.toList());
        return returnList;
    }

    @Override
    public AjaxResult test() {
        R<LoginUser> userResult = remoteUserService.getUserInfo(SecurityUtils.getLoginUser().getSysUser().getEmail(), SecurityConstants.INNER);
        System.out.println("用户邮箱："+SecurityUtils.getLoginUser().getSysUser().getEmail());
        System.out.println("用户名"+SecurityUtils.getLoginUser().getUsername());
        return AjaxResult.success(userResult);
    }

    public RecevingInfo getInfoByRoleId(Long roleId, int type){
        System.out.println("用户roleId："+roleId);
        RecevingInfo info = new RecevingInfo();
        info.setType(type);
        double price = BasePrice.getPriceByCode(type);
        if(roleId > 4 || roleId == 1){
            //管理员1 支持及维护人员5 审核6 财务会计人员7无需付费进行购买
            System.out.println("进入内部计算价格流程");
            info.setValue(1.0);
            info.setFormula("管理员、支持及维护人员、审核、财务会计人员无需付费进行升级（测试时设置为1）");
        }else if(roleId == 2){
            //注册用户升级  直接计算金额
            System.out.println("进入普通用户升级计算价格流程");
            info.setFormula("当前所选会员需支付金额："+price);
            info.setValue(price);
        }else if(roleId == 4){
            if(type == 1 || type ==0){
                info.setFormula("续费年度VIP不支持降级购买其他服务");
                info.setValue(0.0);
            }else {
                //VIP续费  直接计算金额
                System.out.println("进入年度vip用户计算价格流程");
                info.setFormula("续费年度VIP所需支付金额："+price);
                info.setValue(price);
            }
        }else if(roleId == 3){
            if(type == 0){
                info.setFormula("续费购买月度L3会员:"+price+"/月");
                info.setValue(price);
                return info;
            }else if(type == 1){
                info.setFormula("续费年度L3会员:"+price+"/年");
                info.setValue(price);
                return info;
            }
            //付费用户升级 需要根据当前用户等级以及会员时间判断差价
            //获取付费用户当前有效时间
            System.out.println("进入年度vip用户计算价格流程");
            R<SysUserLeveDate> userResult = remoteUserService.userLevel(SecurityUtils.getUserId());
            if (R.FAIL == userResult.getCode())
            {
                throw new ServiceException(userResult.getMsg());
            }

            if (StringUtils.isNull(userResult))
            {
                throw new ServiceException("后台异常，请稍后再试");
            }

            if (StringUtils.isNull(userResult.getData()))
            {
                //没有找到对应数据 将用户角色更改为2注册用户
                info.setFormula("升级年度VIP："+price);
                info.setValue(price);
                return info;
            }
            //拿到数据了 根据对应数据计算剩余金额
            SysUserLeveDate userInfo = userResult.getData();
            System.out.println("userInfo:"+userInfo);

            double basePrice = BasePrice.getPriceByCode(type);
            //todo  具体计算
            double monthAvg = DoubleCalculate.divide(BasePrice.getPriceByCode(1),12);
            //剩余月数 会员总有效期月数-已使用月数
            long month = DateUtils.getMonthDiff(userInfo.getExpireTime(),userInfo.getStartTime()) - DateUtils.getMonthDiff(userInfo.getStartTime(),new Date());
            month = month >0 ? month : 0;
            //余额
            double balance = DoubleCalculate.subtract(basePrice, (DoubleCalculate.multiply(monthAvg, month)));
            if(balance >= 0){
                System.out.println("抵扣小于500");
                info.setValue(DoubleCalculate.subtract(basePrice,(DoubleCalculate.multiply(monthAvg,month))));
                String formula = ""+basePrice+"-(原会员月均价"+monthAvg+" x 剩余会员月数"+month+")="+info.getValue();
                info.setFormula(formula);
            }else {
                //balance小于0 剩余会员月数价值>500
                System.out.println("抵扣大于500");
                info.setValue(0);
                String formula = "当前剩余会员月数："+month+" x 月均价"+monthAvg+"="+(DoubleCalculate.multiply(monthAvg, month)+",大于升级原所需金额500,本次升级无需扣费,但剩余L3月数清零");
                info.setFormula(formula);
            }
            //info.setValue(DoubleCalculate.subtract(basePrice,(DoubleCalculate.multiply(monthAvg,month))));
            //String formula = ""+basePrice+"-(原会员月均价"+monthAvg+" x 剩余会员月数"+month+")="+info.getValue();
            //System.out.println("formula"+formula);
            //info.setFormula(formula);

            System.out.println("info"+info);
        }
        return info;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public ReduceResultDto reduceBalance(Long userId, BigDecimal price){
        ReduceResultDto dto = new ReduceResultDto();
        //查询账户表 判断余额是否充足 充足就执行扣款、升级、修改订单状态 失败则修改订单状态并提示用户余额不足
        UserAccountDto userAccount = orderMapper.getUserAccountByUserId(userId);
        UserBalance userBalance = new UserBalance();
        if(StringUtils.isNotNull(userAccount)){
            userAccount.setTotal(userAccount.getUsdt().add(userAccount.getUsdc()).add(userAccount.getBusd()));
        }else {
            userAccount = new UserAccountDto();
        }

        if(userAccount.getTotal().compareTo(price) >= 0){
            //余额充足
            //先扣款 扣款成功再升级用户
            UserAccountDto newAccount = new UserAccountDto();
            BeanUtils.copyProperties(userAccount,newAccount);
            if(newAccount.getUsdt().compareTo(price) >=0){
                //usdt足够支付
                newAccount.setUsdt(newAccount.getUsdt().subtract(price));
                userBalance.setBalanceUSDT(price);
            }else{
                //usdt不够支付 继续判断usdc
                price = price.subtract(newAccount.getUsdt());
                userBalance.setBalanceUSDT(newAccount.getUsdt());
                newAccount.setUsdt(BigDecimal.valueOf(0));
                if(newAccount.getUsdc().compareTo(price) >=0){
                    newAccount.setUsdc(newAccount.getUsdc().subtract(price));
                    userBalance.setBalanceUSDC(price);
                }else {
                    price = price.subtract(newAccount.getUsdc());
                    userBalance.setBalanceUSDC(newAccount.getUsdc());
                    newAccount.setUsdc(BigDecimal.valueOf(0));
                    if(newAccount.getBusd().compareTo(price) >=0){
                        newAccount.setBusd(newAccount.getBusd().subtract(price));
                        userBalance.setBalanceUSDC(price);
                    }else {
                        return null;
                    }
                }
            }


            //先修改用户对应的账户余额表
            if(orderMapper.updateUserAccount(newAccount,userAccount.getUsdt(),userAccount.getUsdc(),userAccount.getBusd())){
                dto.setUa(userAccount);
                dto.setUb(userBalance);
                return dto;
            }else {
                //余额不足 此情况说明有其他线程先抢占了资源 更改了数据库数据 重新获取余额再次进行判断
                //throw new RuntimeException("余额不足");
                return null;
            }
        }else {
            //余额不足 修改订单状态为失败并提示用户余额不足
            //throw new RuntimeException("余额不足");
            return null;
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public boolean reduce(){
        //查询用户当前账户详情
        UserAccountDto account = orderMapper.getUserAccountByUserId(SecurityUtils.getUserId());
        System.out.println(account.getUsdt());
        if(account.getUsdt().compareTo(BigDecimal.valueOf(100) ) < 0){
            throw new RuntimeException("余额不足");
        }
        UserAccountDto newAccount = new UserAccountDto();
        BeanUtils.copyProperties(account,newAccount);

        newAccount.setUsdt(newAccount.getUsdt().subtract(BigDecimal.valueOf(100)));
        boolean result = orderMapper.updateUserAccount(newAccount, account.getUsdt(), account.getUsdc(), account.getBusd());
        if(!result){
            throw new RuntimeException("余额状态更新，请重试");
        }
        return result;
    }



}
