package server

import (
	"fmt"
	"net/http"
	"runtime/debug"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	domain "github.com/haydenhargreaves/Potion/internal/domain/server"
	"github.com/haydenhargreaves/Potion/internal/infrastructure/logging"
)

// DepedencyInjectionMiddleware injects the dependencies into the context set. This is a middleware
// that is used to apply the required services.
//
// DEPRECATED: As of September 4th, 2025.
// func DepedencyInjectionMiddleware(deps *domain.InjectedDependencies) gin.HandlerFunc {
// 	return func(ctx *gin.Context) {
// 		ctx.Set("deps", deps)
// 		ctx.Next()
// 	}
// }

// JwtAuthMiddleWare handles collection the JWT from the browser's cookies and setting the
// appropriate data. If the data is not found, this middleware will do effectively nothing, by not
// setting any values. Protected routes can use this lack of a value as a sign that the user is not
// logged in and direct the user to login.
func JwtAuthMiddleWare(jwtSecretKey []byte) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// JWT cookie not found
		tokenString, err := ctx.Cookie("jwt_token")
		if err != nil {
			ctx.Next()
			return
		}

		claims := &domain.JwtClaims{}

		token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
			}
			return jwtSecretKey, nil
		})

		// Error occurred when parsing
		if err != nil {
			ctx.Next()
			return
		}

		// NOTE: If we need deeper error handling
		// if err != nil {
		// 	if errors.Is(err, jwt.ErrSignatureInvalid) {
		// 		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature"})
		// 	} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
		// 		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Token expired or not yet valid"})
		// 	} else {
		// 		log.Printf("JWT parsing error: %v", err)
		// 		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
		// 	}
		// 	ctx.Abort()
		// 	return
		// }

		// Token is invalid
		if !token.Valid {
			ctx.Next()
			return
		}

		// Found: Set the values
		ctx.Set("userId", claims.UserId)
		ctx.Set("userEmail", claims.Email)
		ctx.Next()
	}
}

func RecoveryMiddleware(logs []logging.Logger) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		defer func() {
			if r := recover(); r != nil {
				// Log the panic with stack trace
				err := fmt.Errorf("panic recovered: %v\n%s", r, debug.Stack())
				logging.LogAll(logs, logging.LogLevelFatal, "[PANIC RECOVERY] %s\n", err)

				ctx.JSON(http.StatusOK, gin.H{
					"status":  http.StatusOK,
					"error":   "API_PANIC_RECOVERED",
					"message": err.Error(),
				})

				// Determine the content type of the request for appropriate response
				// acceptHeader := ctx.Request.Header.Get("Accept")
				//
				// // Customize the response based on the request type (e.g., HTML vs. JSON)
				// if strings.Contains(acceptHeader, "text/html") {
				// 	// For browser requests (HTML), redirect to an error page or render a template
				// 	ctx.HTML(http.StatusInternalServerError, "error.html", gin.H{
				// 		"title":   "Something went wrong",
				// 		"message": "An unexpected error occurred. Please try again later.",
				// 	})
				// } else if strings.Contains(acceptHeader, "application/json") || ctx.Request.Method == http.MethodPost {
				// 	// For API requests (JSON), return a JSON error response
				// 	ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
				// 		"error":   "An internal server error occurred.",
				// 		"message": "We're working to fix the problem. Please try again later.",
				// 		// You might include a unique error ID here for tracking
				// 	})
				// } else {
				// 	// Fallback for other content types
				// 	ctx.AbortWithStatus(http.StatusInternalServerError)
				// }
			}
		}()
		ctx.Next()
	}
}
