package com.cyksj.web.controller.advertisement;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.util.Codec;
import com.cyksj.common.util.IoKit;
import com.cyksj.common.util.Xmls;
import com.cyksj.dto.Result;
import com.cyksj.enums.GatewayApiCode;
import com.cyksj.enums.GatewayResponse;
import com.cyksj.mapper.WxAppMapper;
import com.cyksj.model.dto.H5JsPayParams;
import com.cyksj.model.entity.AdvertisementOrderDon;
import com.cyksj.model.entity.AdvertisementUser;
import com.cyksj.model.entity.WxApp;
import com.cyksj.model.request.WeChatPayRequest;
import com.cyksj.model.views.PaySuccessViews;
import com.cyksj.redis.RedisService;
import com.cyksj.service.advertisement.AdvertisementOrderDonService;
import com.cyksj.service.advertisement.AdvertisementUserService;
import com.cyksj.web.util.StpUserUtil;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;

/**
 * @author chan
 * @date 2023/5/16 11:49 AM
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/applets/advertisement/order")
public class AdvertisementOrderDonController {

    private static final String OPEN_KEY = "openKey";
    
    private final HttpServletRequest request;
    
    private final AdvertisementUserService advertisementUserService;

    private final AdvertisementOrderDonService advertisementOrderDonService;
    
    private final WxAppMapper wxAppMapper;
    

    @PostMapping("/post/pay")
    public Result<H5JsPayParams> pay(@RequestBody @Validated WeChatPayRequest weChatPayRequest) throws Exception {
        final String methodName = "广告投放微信支付";
        BigDecimal donMoney = weChatPayRequest.getDonMoney();
        log.info("{}[start] donMoney:{} params:{}", methodName, donMoney, weChatPayRequest);

        if (StringUtils.isBlank(weChatPayRequest.getAppId())) {
            throw BusinessRuntimeException.getInstance("缺少必填参数appId");
        }
        WxApp wxApp = wxAppMapper.selectOne(Wrappers.lambdaQuery(WxApp.class).eq(WxApp::getAppId, weChatPayRequest.getAppId()));
        if (wxApp == null) {
            throw BusinessRuntimeException.getInstance("app不存在.");
        }
        AdvertisementOrderDon.Source source;
        AdvertisementUser user;
        if ("小程序".equals(wxApp.getCategory())) {
            
            //小程序支付
            user = advertisementUserService.getById(StpUserUtil.getLoginIdAsLong());
            source = AdvertisementOrderDon.Source.Mini_Program;
        }else {

            source = AdvertisementOrderDon.Source.WeChat;
            AtomicReference<String> openKey = new AtomicReference<>();
            Cookie[] cookies = request.getCookies();
            Stream.of(cookies).forEach((cookie) -> {
                if (StringUtils.equals(cookie.getName(), OPEN_KEY)) {
                    openKey.set(cookie.getValue());
                }
            });
            if (StringUtils.isBlank(openKey.get())) {
                throw BusinessRuntimeException.getInstance("您还未授权.");
            }
            String payOpenId = Codec.DoBase64.custom().setData(openKey.get()).decodeAsText();

            user = new AdvertisementUser();
            user.setOpenId(payOpenId);
            user.setId(0L);
        }
        
      
        H5JsPayParams payParams = advertisementOrderDonService.pay(weChatPayRequest.getPopularizeId()
                , donMoney.setScale(0, RoundingMode.DOWN), weChatPayRequest.getAppId(), user, source
                , weChatPayRequest.getCallback(), weChatPayRequest.getCallbackType());


        return GatewayResponse.SUCCESS.newBuilder().toResult(payParams);
    }

    @GetMapping("/isPay/{orderId}")
    public Result<PaySuccessViews> isPay(@PathVariable @NonNull Long orderId) {
        return GatewayResponse.SUCCESS.newBuilder().toResult(advertisementOrderDonService.isPay(orderId));
    }

    @PostMapping("/prepay/notify")
    public void prepayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String xml = IoKit.toString(request.getInputStream());
        log.info("=== 微信支付的回调: \n {}", xml);

        // 解析xml
        Map<String, String> map = Xmls.toMap(xml);

        // 支付失败
        if (!StringUtils.equals("SUCCESS", map.get("return_code")) || !StringUtils.equals("SUCCESS", map.get("result_code"))) {
            throw BusinessRuntimeException.getInstance("支付失败.");
        }

        advertisementOrderDonService.prepayNotify(map);
        String toWeChatXmlResponse = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";

        OutputStream out = null;
        try {
            out = response.getOutputStream();
            IoKit.write(toWeChatXmlResponse, out);
        } catch (Throwable e) {
            throw new BusinessRuntimeException(e,"微信支付回调错误.");
        } finally {
            IoKit.close(out);
        }
    }
}
