package com.zanxiang.game.module.sdk.service.pay;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zanxiang.game.module.mybatis.entity.Order;
import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
import com.zanxiang.game.module.sdk.enums.OrderStateEnum;
import com.zanxiang.game.module.sdk.listener.OrderPaySuccessEvent;
import com.zanxiang.game.module.sdk.pojo.dto.GamePayWayDTO;
import com.zanxiang.game.module.sdk.pojo.dto.PlatformOrderDTO;
import com.zanxiang.game.module.sdk.pojo.dto.ProductPayParamDTO;
import com.zanxiang.game.module.sdk.service.IAliApiService;
import com.zanxiang.game.module.sdk.service.IGamePayWayService;
import com.zanxiang.game.module.sdk.service.IOrderService;
import com.zanxiang.game.module.sdk.util.RedisUtil;
import com.zanxiang.module.util.DateUtil;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.exception.BaseException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * @author : lingfeng
 * @time : 2022-09-28
 * @description : 支付超类
 */
@Slf4j
public abstract class PayBaseService {

    @Lazy
    @Autowired
    public IOrderService orderService;

    @Lazy
    @Autowired
    public IGamePayWayService gamePayWayService;

    @Lazy
    @Autowired
    private ApplicationContext applicationContext;

    @Lazy
    @Autowired
    private RedisUtil<String> redisUtil;

    @Lazy
    @Autowired
    private IAliApiService aliApiService;

    /**
     * 创建订单支付参数
     *
     * @param product : 支付参数
     */
    public Map<String, Object> payCreate(ProductPayParamDTO product) {
        try {
            //获取订单信息
            PlatformOrderDTO platformOrderDTO = orderService.getByOrderId(product.getOutTradeNo());
            if (platformOrderDTO == null) {
                throw new BaseException("参数错误, 订单信息不存在");
            }
            Long gameId = platformOrderDTO.getGameId();
            //根据订单中游戏id，获取游戏的支付方式
            GamePayWayDTO gamePayWayDTO = gamePayWayService.getGamePayWay(gameId, product.getPayWay(), product.getPayDevice());
            product.setProductId(platformOrderDTO.getProductId());
            product.setSubject(platformOrderDTO.getProductName());
            product.setGameId(gameId);
            product.setTotalFee(String.valueOf(platformOrderDTO.getAmount()));
            product.setOutTradeNo(platformOrderDTO.getOrderId());
            return this.create(product, gamePayWayDTO);
        } catch (Exception e) {
            log.error("订单支付参数生成异常, ProductPayParamBO : {} , e: {}", JsonUtil.toString(product), e.getMessage());
            throw new BaseException("订单支付参数生成异常");
        }
    }

    /**
     * 支付成功逻辑
     *
     * @param orderNo         订单号
     * @param realAmount      真实金额
     * @param merchantOrderNo 商户号
     * @return : 返回支付状态
     */
    public Boolean paySuccess(String orderNo, String realAmount, String merchantOrderNo) {
        Order order = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderId, orderNo));
        if (order == null) {
            return Boolean.FALSE;
        }
        //已支付情况，直接返回成功
        if (order.getStatus().equals(OrderStateEnum.SUCCESS_PAY.getCode())) {
            return Boolean.TRUE;
        }
        //订单更新
        boolean result = orderService.update(new LambdaUpdateWrapper<Order>()
                .set(Order::getRealAmount, new BigDecimal(realAmount))
                .set(Order::getMerchantOrderNo, merchantOrderNo)
                .set(Order::getStatus, OrderStateEnum.SUCCESS_PAY.getCode())
                .set(Order::getPayTime, LocalDateTime.now())
                .eq(Order::getOrderId, orderNo));
        if (result) {
            OrderPaySuccessEvent orderPaySuccessEvent = new OrderPaySuccessEvent(this, order.getOrderId());
            applicationContext.publishEvent(orderPaySuccessEvent);
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 订单添加过期时间
     *
     * @param orderId : 订单id
     */
    public void orderExpire(String orderId) {
        //过期时间
        double expire = (double) DateUtil.localDateTimeToMilli(LocalDateTime.now().plusMinutes(10));
        //设置缓存
        redisUtil.addZSet(RedisKeyConstant.ORDER_EXPIRE, orderId, expire);
        log.error("订单添加过期缓存, orderId : {}, expire : {}", orderId, expire);
    }

    public void listenCall(Long gameId, String param) {
        try {
            aliApiService.listenCall(gameId, param);
        } catch (Exception e) {
            log.error("监听呼叫调用异常, gameId : {}, param : {}", gameId.toString(), param);
        }
    }

    /**
     * 支付调起
     *
     * @param product       : 调起支付的参数
     * @param gamePayWayDTO 游戏dto支付方式
     * @return {@link Map}<{@link String}, {@link Object}>
     */
    public abstract Map<String, Object> create(ProductPayParamDTO product, GamePayWayDTO gamePayWayDTO);

    /**
     * 支付异步回调
     *
     * @param request  : 回调请求
     * @param response : 回调返回
     * @return : 返回回调结果
     * @throws IOException : io异常
     */
    public abstract String notify(HttpServletRequest request, HttpServletResponse response) throws IOException;

    /**
     * 关闭订单
     *
     * @param platformOrderDTO 平台订单dto
     */
    public abstract void closeOrder(PlatformOrderDTO platformOrderDTO);
}
