package handler

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/gouki/lunar-server/internal/config"
	"github.com/gouki/lunar-server/internal/model"
	"github.com/gouki/lunar-server/internal/service"
)

// CreateOrder 创建订单
// 安全约束：金额与商品名一律以服务端商品表为准，不信任客户端传入值
func CreateOrder(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"code": 401,
			"msg":  "未授权",
		})
		return
	}

	var req struct {
		Type      string `json:"type" binding:"required"`      // wish:许愿 vip:会员
		ProductID uint   `json:"productId" binding:"required"` // 商品ID
		Content   string `json:"content"`                      // 许愿内容（许愿类型需要）
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "参数错误",
		})
		return
	}

	// 服务端定价：按商品 ID 查库取价格，防止客户端篡改金额
	wishService := service.NewWishService()
	product, err := wishService.GetWishProductByID(req.ProductID)
	if err != nil || product.Status != 1 {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "商品不存在或已下架",
		})
		return
	}

	if req.Type == "wish" {
		if req.Content == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"code": 400,
				"msg":  "请输入许愿内容",
			})
			return
		}
		if len([]rune(req.Content)) > 100 {
			c.JSON(http.StatusBadRequest, gin.H{
				"code": 400,
				"msg":  "许愿内容超过 100 字限制",
			})
			return
		}
	} else {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "不支持的订单类型",
		})
		return
	}

	orderService := service.NewOrderService()
	order := &model.Order{
		UserID:      userID.(uint),
		Type:        req.Type,
		ProductID:   product.ID,
		ProductName: product.Name,
		Amount:      product.Price, // 金额以商品表为准
		Remark:      req.Content,   // 许愿内容暂存订单，支付成功后才创建许愿
	}

	if err := orderService.CreateOrder(order); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "创建订单失败",
		})
		return
	}

	// 创建微信支付订单
	payParams, err := orderService.CreateWechatPayOrder(order, "")
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "创建支付订单失败",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{
			"orderId":   order.ID,
			"orderNo":   order.OrderNo,
			"payParams": payParams,
		},
	})
}

// paySignOf 计算支付回调签名：HMAC-SHA256(orderNo|transactionId, APIKEY)
// 过渡方案：真实微信支付 V3 回调验签接入前的内部协议
func paySignOf(orderNo, transactionID, key string) string {
	mac := hmac.New(sha256.New, []byte(key))
	mac.Write([]byte(orderNo + "|" + transactionID))
	return hex.EncodeToString(mac.Sum(nil))
}

// PayNotify 支付回调：必须携带 X-Pay-Sign 签名头，验签通过且幂等处理
func PayNotify(c *gin.Context) {
	cfg := config.Load()
	if cfg.Wechat.PayKey == "" {
		// 未配置支付密钥时拒绝一切回调，避免裸奔
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"code": "FAIL",
			"msg":  "支付服务未配置",
		})
		return
	}

	var req struct {
		OrderNo       string `json:"orderNo" binding:"required"`
		TransactionID string `json:"transactionId" binding:"required"`
		Status        string `json:"status"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": "FAIL",
			"msg":  "参数错误",
		})
		return
	}

	// 验签：恒定时间比较，防时序攻击
	sign := c.GetHeader("X-Pay-Sign")
	expected := paySignOf(req.OrderNo, req.TransactionID, cfg.Wechat.PayKey)
	if sign == "" || !hmac.Equal([]byte(sign), []byte(expected)) {
		c.JSON(http.StatusUnauthorized, gin.H{
			"code": "FAIL",
			"msg":  "签名验证失败",
		})
		return
	}

	if req.Status != "SUCCESS" {
		c.JSON(http.StatusOK, gin.H{
			"code": "SUCCESS",
			"msg":  "OK",
		})
		return
	}

	orderService := service.NewOrderService()
	if err := orderService.HandlePayNotify(req.OrderNo, req.TransactionID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": "FAIL",
			"msg":  "处理失败",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": "SUCCESS",
		"msg":  "OK",
	})
}

// GetPayStatus 获取支付状态（支持订单号或订单 ID）
func GetPayStatus(c *gin.Context) {
	param := c.Param("orderId")

	orderService := service.NewOrderService()
	order, err := orderService.GetOrderByOrderNo(param)
	if err != nil {
		// 兼容传数字 ID 的调用方
		if id, convErr := strconv.Atoi(param); convErr == nil {
			order, err = orderService.GetOrderByID(uint(id))
		}
	}
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{
			"code": 404,
			"msg":  "订单不存在",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{
			"orderId": order.ID,
			"orderNo": order.OrderNo,
			"status":  order.Status,
			"payTime": order.PayTime,
		},
	})
}
