package cn.newfeifan.mall.module.distri.service.usertopupconsumptionpointsorder;

import cn.newfeifan.mall.framework.common.exception.ErrorCode;
import cn.newfeifan.mall.module.distri.config.OrderProperties;
import cn.newfeifan.mall.module.distri.constant.DistriConstants;
import cn.newfeifan.mall.module.distri.controller.app.consumptionchangelog.vo.ConsumptionChangeLogSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.app.integral.vo.IntegralSaveReqVO;
import cn.newfeifan.mall.module.distri.convert.usertopupconsumptionpointsorder.UserTopUpConsumptionPointsOrderConvert;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.orderpercentage.OrderPercentageDO;
import cn.newfeifan.mall.module.distri.dal.redis.no.OrderNoRedisDAO;
import cn.newfeifan.mall.module.distri.enums.ConsumptionEnum;
import cn.newfeifan.mall.module.distri.service.consumptionchangelog.ConsumptionChangeLogService;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.orderpercentage.OrderPercentageService;
import cn.newfeifan.mall.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
import cn.newfeifan.mall.module.member.dal.dataobject.user.MemberUserDO;
import cn.newfeifan.mall.module.member.dal.mysql.user.MemberUserMapper;
import cn.newfeifan.mall.module.member.service.user.MemberUserService;
import cn.newfeifan.mall.module.pay.dal.dataobject.app.PayAppDO;
import cn.newfeifan.mall.module.pay.dal.dataobject.order.PayOrderDO;
import cn.newfeifan.mall.module.pay.dal.mysql.order.PayOrderMapper;
import cn.newfeifan.mall.module.pay.service.app.PayAppService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import cn.newfeifan.mall.module.distri.controller.app.usertopupconsumptionpointsorder.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.usertopupconsumptionpointsorder.UserTopUpConsumptionPointsOrderDO;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.util.object.BeanUtils;

import cn.newfeifan.mall.module.distri.dal.mysql.usertopupconsumptionpointsorder.UserTopUpConsumptionPointsOrderMapper;


import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.newfeifan.mall.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.newfeifan.mall.framework.web.core.util.WebFrameworkUtils.getTerminal;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

/**
 * 用户充值消费分订单 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
@Slf4j
public class UserTopUpConsumptionPointsOrderServiceImpl implements UserTopUpConsumptionPointsOrderService {

    @Resource
    private UserTopUpConsumptionPointsOrderMapper userTopUpConsumptionPointsOrderMapper;
    @Resource
    private OrderPercentageService orderPercentageService;
    @Resource
    private IntegralService integralService;
    @Resource
    private ConsumptionChangeLogService consumptionChangeLogService;
    @Resource
    private OrderNoRedisDAO orderNoRedisDAO;
    @Resource
    private OrderProperties orderProperties;
    @Resource
    private PayAppService appService;
    @Resource
    private PayOrderMapper payOrderMapper;
    @Resource
    private MemberUserService memberUserService;

    @Override
    public UserTopUpConsumptionPointsOrderInfoRespVO createUserTopUpConsumptionPointsOrder(UserTopUpConsumptionPointsOrderSaveReqVO createReqVO) {
        // 初始化订单
        orderInit(createReqVO);

        UserTopUpConsumptionPointsOrderDO userTopUpConsumptionPointsOrder = BeanUtils.toBean(createReqVO, UserTopUpConsumptionPointsOrderDO.class);
        userTopUpConsumptionPointsOrderMapper.insert(userTopUpConsumptionPointsOrder);

        // 创建支付订单
        PayOrderDO payOrder = createPayOrder(userTopUpConsumptionPointsOrder);
        userTopUpConsumptionPointsOrder.setPayOrderId(payOrder.getId());

        // 同步支付订单id
        userTopUpConsumptionPointsOrderMapper.updateById(userTopUpConsumptionPointsOrder);

        // 返回
        return UserTopUpConsumptionPointsOrderInfoRespVO.builder()
                .id(userTopUpConsumptionPointsOrder.getId())
                .payOrderId(userTopUpConsumptionPointsOrder.getPayOrderId())
                .build();
    }

    /**
     * 创建支付订单
     *
     * @param createReqVO 充值订单信息
     * @return 支付订单
     */
    private PayOrderDO createPayOrder(UserTopUpConsumptionPointsOrderDO createReqVO) {
        // 校验 App
        PayAppDO app = appService.validPayApp(orderProperties.getAppId());

        PayOrderDO payOrderDO = UserTopUpConsumptionPointsOrderConvert.INSTANCE.convert(createReqVO, orderProperties);
        payOrderDO.setNotifyUrl(app.getOrderNotifyUrl());
        payOrderMapper.insert(payOrderDO);
        return payOrderDO;
    }

    /**
     * 订单转换
     *
     * @param createReqVO       订单信息
     */
    private void orderInit(UserTopUpConsumptionPointsOrderSaveReqVO createReqVO) {
        // 计算百分比
        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();

        if(createReqVO.getPayPrice() < Double.parseDouble(orderPercentageDO.getUserTopUpConsumptionPoints())){
            ErrorCode ERROR = new ErrorCode(1_002_030_038, "用户充值金额不得小于:" + orderPercentageDO.getUserTopUpConsumptionPoints());
            throw exception(ERROR);
        }

        createReqVO.setUserId(getLoginUserId());
        createReqVO.setUserIp(getClientIP());
        createReqVO.setTerminal(getTerminal());
        createReqVO.setSubject("消费分");
        createReqVO.setPayStatus(false);
        createReqVO.setNo(orderNoRedisDAO.generate(OrderNoRedisDAO.TRADE_ORDER_NO_PREFIX));

        // 转换金额
        createReqVO.setPayPrice(createReqVO.getPayPrice() * DistriConstants.ONE_HUNDRED);
        createReqVO.setTopUpConsumptionPoints(createReqVO.getPayPrice() * DistriConstants.PERCENT);

        // 根据充值金额计算实际到账金额
        if(createReqVO.getTopUpConsumptionPoints() >= Double.parseDouble(orderPercentageDO.getTriggerMagnificationPoints()) * DistriConstants.INTEGRAL_PAGE2DB){
        createReqVO.setPracticalConsumptionPoints((long) (createReqVO.getTopUpConsumptionPoints() * Double.parseDouble(orderPercentageDO.getConsumptionMagnification())));
        } else {
            createReqVO.setPracticalConsumptionPoints(createReqVO.getTopUpConsumptionPoints().longValue());
        }
        createReqVO.setPercentTemplate(JSON.toJSONString(orderPercentageDO));
    }

    @Override
    public void updateUserTopUpConsumptionPointsOrder(UserTopUpConsumptionPointsOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateUserTopUpConsumptionPointsOrderExists(updateReqVO.getId());
        // 更新
        UserTopUpConsumptionPointsOrderDO updateObj = BeanUtils.toBean(updateReqVO, UserTopUpConsumptionPointsOrderDO.class);
        userTopUpConsumptionPointsOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserTopUpConsumptionPointsOrder(Long id) {
        // 校验存在
        validateUserTopUpConsumptionPointsOrderExists(id);
        // 删除
        userTopUpConsumptionPointsOrderMapper.deleteById(id);
    }

    private void validateUserTopUpConsumptionPointsOrderExists(Long id) {
        if (userTopUpConsumptionPointsOrderMapper.selectById(id) == null) {
            throw exception(USER_TOP_UP_CONSUMPTION_POINTS_ORDER_NOT_EXISTS);
        }
    }

    @Override
    public UserTopUpConsumptionPointsOrderDO getUserTopUpConsumptionPointsOrder(Long id) {
        return userTopUpConsumptionPointsOrderMapper.selectById(id);
    }

    @Override
    public PageResult<UserTopUpConsumptionPointsOrderDO> getUserTopUpConsumptionPointsOrderPage(UserTopUpConsumptionPointsOrderPageReqVO pageReqVO) {
        return userTopUpConsumptionPointsOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public void topUpConsumptionPoints(PayOrderDO payOrderDO) {
        UserTopUpConsumptionPointsOrderDO topUpOrder = userTopUpConsumptionPointsOrderMapper.selectById(payOrderDO.getMerchantOrderId());

        log.info("充值订单对象:{}", topUpOrder);
        if(topUpOrder.getPayStatus()){
            log.info("充值订单状态为已支付,return结束!");
            return;
        }

        // 修改订单状态
        userTopUpConsumptionPointsOrderMapper.updateById(UserTopUpConsumptionPointsOrderDO.builder()
                .id(topUpOrder.getId())
                .payStatus(true)
                .payTime(payOrderDO.getSuccessTime())
                .payChannelCode(payOrderDO.getChannelCode())
                .finishTime(payOrderDO.getSuccessTime())
                .build());

        // 获取钱包
        IntegralDO integralDO = integralService.selectByUser(topUpOrder.getUserId());
        integralDO.setConsumptionPoints(integralDO.getConsumptionPoints() + topUpOrder.getPracticalConsumptionPoints());
        integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));

        // 消费分变动日志
        consumptionChangeLogService.createConsumptionChangeLog(ConsumptionChangeLogSaveReqVO.builder()
                .userId(topUpOrder.getUserId())
                .consumptionStatus(ConsumptionEnum.TOP_UP_GET.getType())
                .consumptionPoints(topUpOrder.getPracticalConsumptionPoints())
                .afterConsumptionPoints(integralDO.getConsumptionPoints())
                .practicalConsumptionPoints(topUpOrder.getTopUpConsumptionPoints())
                .generateUserId(topUpOrder.getUserId())
                .build());

        //计算充值消费分超过设定金额将用户标志为代理商
        MemberUserDO user = memberUserService.getUser(topUpOrder.getUserId());
        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
        if(topUpOrder.getTopUpConsumptionPoints() >= Long.parseLong(orderPercentageDO.getAgentQuota()) && !user.getAgent()){
            user.setAgent(true);
            memberUserService.updateUser(BeanUtils.toBean(user, MemberUserUpdateReqVO.class));
        }
    }

}