package middleware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"

	"infogenie-backend/config"
)

type AuthCenterUser struct {
	Account      string  `json:"account"`
	Username     string  `json:"username"`
	Email        string  `json:"email"`
	Level        int     `json:"level"`
	SproutCoins  float64 `json:"sproutCoins"`
	AvatarURL    string  `json:"avatarUrl"`
	WebsiteURL   string  `json:"websiteUrl"`
	Bio          string  `json:"bio"`
	CheckInDays  int     `json:"checkInDays"`
	CheckInStreak int    `json:"checkInStreak"`
}

type VerifyResponse struct {
	Valid     bool            `json:"valid"`
	User      *AuthCenterUser `json:"user,omitempty"`
	Error     string          `json:"error,omitempty"`
	BanReason string          `json:"banReason,omitempty"`
}

func verifyTokenWithAuthCenter(tokenStr string) (*VerifyResponse, error) {
	body, _ := json.Marshal(map[string]string{"token": tokenStr})

	url := config.Cfg.AuthCenter.APIURL + "/api/auth/verify"
	req, err := http.NewRequest("POST", url, bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Auth-Client", "infogenie")
	req.Header.Set("X-Auth-Client-Name", "万象口袋")

	client := &http.Client{Timeout: 10 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求认证中心失败: %w", err)
	}
	defer resp.Body.Close()

	data, _ := io.ReadAll(resp.Body)

	if resp.StatusCode == 401 {
		return &VerifyResponse{Valid: false, Error: "invalid token"}, nil
	}

	var result VerifyResponse
	if err := json.Unmarshal(data, &result); err != nil {
		return nil, fmt.Errorf("解析认证响应失败: %w", err)
	}
	return &result, nil
}

func extractToken(c *gin.Context) string {
	auth := c.GetHeader("Authorization")
	if strings.HasPrefix(auth, "Bearer ") {
		return auth[7:]
	}
	return auth
}

func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenStr := extractToken(c)
		if tokenStr == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"success": false, "message": "缺少认证token"})
			c.Abort()
			return
		}

		result, err := verifyTokenWithAuthCenter(tokenStr)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": "认证服务暂时不可用"})
			c.Abort()
			return
		}

		if !result.Valid || result.User == nil {
			msg := "Token无效或已过期"
			if result.BanReason != "" {
				msg = "账户已被封禁"
			}
			c.JSON(http.StatusUnauthorized, gin.H{"success": false, "message": msg})
			c.Abort()
			return
		}

		c.Set("account", result.User.Account)
		c.Set("username", result.User.Username)
		c.Set("email", result.User.Email)
		c.Set("sprout_coins", result.User.SproutCoins)
		c.Set("auth_user", result.User)
		c.Next()
	}
}

func OptionalJWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenStr := extractToken(c)
		if tokenStr != "" {
			result, err := verifyTokenWithAuthCenter(tokenStr)
			if err == nil && result.Valid && result.User != nil {
				c.Set("account", result.User.Account)
				c.Set("username", result.User.Username)
				c.Set("email", result.User.Email)
				c.Set("sprout_coins", result.User.SproutCoins)
				c.Set("auth_user", result.User)
			}
		}
		c.Next()
	}
}
