package front

import (
	"PaymentCenter/app/constants/common"
	"PaymentCenter/app/constants/errorcode"
	"PaymentCenter/app/http/controllers"
	"PaymentCenter/app/http/entities/front"
	"PaymentCenter/app/models/paychannelmodel"
	"PaymentCenter/app/services"
	"PaymentCenter/app/third/paymentService"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/alipay"
	"github.com/go-pay/gopay/wechat/v3"
	"github.com/qit-team/snow-core/log/logger"
	"io/ioutil"
	"strconv"

	"net/http"
)

// WxCallback	微信支付回调
func WxCallback(c *gin.Context) {
	logger.Info(c, "WxCallback-回调数据", c.Request)
	payChannelId := c.Param("payChannelId")
	logger.Info(c, "WxCallback-回调数据payChannelId", payChannelId)
	if payChannelId == "" {
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}

	// 查询应用下的支付配置
	var payChannelModel paychannelmodel.PayChannel
	payChannelIdInt, _ := strconv.Atoi(payChannelId)
	payChannelModel.Id = int64(payChannelIdInt)
	code := services.PayChannelGet(&payChannelModel)
	if code == errorcode.PayChannelNotFound {
		logger.Error(c, "AliCallback-回调数据未获取到支付配置,404")
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}
	if payChannelModel.ChannelType != common.PAY_CHANNEL_WECHAT_H5 {
		logger.Error(c, "WxCallback-回调数据解析支付配置错误,查询的数据不是当前渠道")
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}

	var wxConfig paymentService.WxPay
	err := json.Unmarshal([]byte(payChannelModel.ExtJson), &wxConfig)
	if err != nil {
		logger.Error(c, "WxCallback-回调数据解析支付配置错误", fmt.Sprintf("错误原因:%s", err.Error()))
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}
	if wxConfig.ApiV3Key == "" || wxConfig.MchId == "" || wxConfig.PrivateKey == "" || wxConfig.SerialNo == "" {
		logger.Error(c, "WxCallback-回调数据解析支付配置错误,解析出来的信息为空")
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}
	wxConfig.AppId = payChannelModel.AppId

	notifyReq, err := wechat.V3ParseNotify(c.Request)
	if err != nil {
		logger.Error(c, "WxCallback-回调数据验签失败", err.Error())
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}

	notifyReqJson, _ := json.Marshal(notifyReq)
	logger.Info(c, "WxCallback-解析微信回调请求的参数到 V3NotifyReq 结构体", string(notifyReqJson))
	err = paymentService.WxPayCallBack(notifyReq, wxConfig)
	if err != nil {
		logger.Error(c, "WxCallback-回调执行失败,失败原因:", err.Error())
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}

	c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
	return
}

// AliCallback	支付宝支付回调
func AliCallback(c *gin.Context) {
	logger.Info(c, "AliCallback-回调数据", c.Request)
	payChannelId := c.Param("payChannelId")
	logger.Info(c, "AliCallback-回调数据APPID", payChannelId)
	if payChannelId == "" {
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}
	// 查询应用下的支付配置
	var payChannelModel paychannelmodel.PayChannel
	payChannelIdInt, _ := strconv.Atoi(payChannelId)
	payChannelModel.Id = int64(payChannelIdInt)
	code := services.PayChannelGet(&payChannelModel)
	if code == errorcode.PayChannelNotFound {
		logger.Error(c, "AliCallback-回调数据未获取到支付配置,404")
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}
	if payChannelModel.ChannelType != common.PAY_CHANNEL_ALIPAY_WEB {
		logger.Error(c, "AliCallback-回调数据解析支付配置错误,查询的数据不是当前渠道")
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}

	var aliConfig paymentService.AliPay
	err := json.Unmarshal([]byte(payChannelModel.ExtJson), &aliConfig)
	if err != nil {
		logger.Error(c, "AliCallback-回调数据解析支付配置错误", fmt.Sprintf("错误原因:%s", err.Error()))
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}
	if aliConfig.AlipayPublicCert == "" || aliConfig.PrivateKey == "" || aliConfig.AppPublicCert == "" || aliConfig.AlipayRootCert == "" {
		logger.Error(c, "AliCallback-回调数据解析支付配置错误,解析出来的信息为空")
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}
	aliConfig.AppId = payChannelModel.AppId

	notifyReq, err := alipay.ParseNotifyToBodyMap(c.Request) // c.Request 是 gin 框架的写法
	if err != nil {
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}

	notifyReqJson, _ := json.Marshal(notifyReq)
	logger.Info(c, "AliCallback-解析支付宝支付异步通知的参数到BodyMap", string(notifyReqJson))
	err = paymentService.ALiCallBack(notifyReq, aliConfig)
	if err != nil {
		logger.Error(c, "AliCallback-回调执行失败,失败原因:", err.Error())
		c.String(http.StatusBadRequest, "%s", "fail")
		return
	}

	c.String(http.StatusOK, "%s", "success")
	return
}

func BrokerWechatUrl(c *gin.Context) {
	url := c.Query("url")
	if url == "" {
		c.String(400, "url is empty")
		return
	}

	method := "GET"
	client := &http.Client{}
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	req.Header.Add("Referer", "https://cardmallpay.85938.cn")
	req.Header.Add("User-Agent", "Apifox/1.0.0 (https://apifox.com)")
	req.Header.Add("Accept", "*/*")
	req.Header.Add("Host", "wx.tenpay.com")
	req.Header.Add("Connection", "keep-alive")

	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer res.Body.Close()

	// 读取响应体
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	// 复制响应头部(可选,根据需要选择需要的头部)
	for name, values := range res.Header {
		// 注意:某些头部(如Content-Length)在转发时可能需要重新计算
		for _, value := range values {
			c.Writer.Header().Add(name, value)
		}
	}

	// 设置状态码
	c.Writer.WriteHeader(res.StatusCode)

	// 写入响应体
	_, err = c.Writer.Write(body)
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}
}

// 首页
func Index(c *gin.Context) {
	c.HTML(200, "index.html", gin.H{})
}

// 获取微信授权链接
func GetWxAuthUrl(c *gin.Context) {
	req, _ := controllers.GetRequest(c).(*front.GetWxAuthUrlRequest)

	url, code := services.GetWxAuthUrl(*req)
	controllers.HandCodeRes(c, url, code)
}

// 通过code获取授权,openid
func GetWxAuth(c *gin.Context) {
	req, _ := controllers.GetRequest(c).(*front.GetWxAuthRequest)
	rsp, code := services.GetWxAuth(*req)
	controllers.HandCodeRes(c, rsp, code)
}