package handler

import (
	"crypto/subtle"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"freeleaps.com/gitea-webhook-ambassador/internal/logger"
	"github.com/golang-jwt/jwt/v5"
)

type AuthMiddleware struct {
	secretKey string
}

func NewAuthMiddleware(secretKey string) *AuthMiddleware {
	logger.Debug("Creating auth middleware with secret key length: %d", len(secretKey))
	return &AuthMiddleware{
		secretKey: secretKey,
	}
}

// LoginRequest represents the login request body
type LoginRequest struct {
	SecretKey string `json:"secret_key"`
}

// LoginResponse represents the login response
type LoginResponse struct {
	Token string `json:"token"`
}

// HandleLogin handles the login API request
func (a *AuthMiddleware) HandleLogin(w http.ResponseWriter, r *http.Request) {
	// Only accept POST requests
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Parse JSON request
	var req LoginRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	// Validate secret key
	if subtle.ConstantTimeCompare([]byte(req.SecretKey), []byte(a.secretKey)) != 1 {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{
			"error": "Invalid secret key",
		})
		return
	}

	// Generate JWT token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"exp": time.Now().Add(24 * time.Hour).Unix(),
		"iat": time.Now().Unix(),
	})

	// Sign the token
	tokenString, err := token.SignedString([]byte(a.secretKey))
	if err != nil {
		logger.Error("Failed to generate token: %v", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	// Return the token
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(LoginResponse{
		Token: tokenString,
	})
}

// Authenticate middleware for protecting routes
func (a *AuthMiddleware) Authenticate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Skip authentication for login page and static assets
		if r.URL.Path == "/login" || strings.HasPrefix(r.URL.Path, "/css/") ||
			strings.HasPrefix(r.URL.Path, "/js/") || strings.HasPrefix(r.URL.Path, "/img/") {
			next.ServeHTTP(w, r)
			return
		}

		// Get token from Authorization header
		authHeader := r.Header.Get("Authorization")
		if authHeader == "" {
			logger.Debug("No Authorization header found")
			http.Redirect(w, r, "/login", http.StatusSeeOther)
			return
		}

		// Remove 'Bearer ' prefix
		tokenString := strings.TrimPrefix(authHeader, "Bearer ")

		// Parse and validate token
		token, err := jwt.Parse(tokenString, 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 []byte(a.secretKey), nil
		})

		if err != nil || !token.Valid {
			logger.Debug("Invalid token: %v", err)
			if r.Header.Get("X-Requested-With") == "XMLHttpRequest" {
				w.WriteHeader(http.StatusUnauthorized)
				json.NewEncoder(w).Encode(map[string]string{
					"error": "Invalid or expired token",
				})
			} else {
				http.Redirect(w, r, "/login", http.StatusSeeOther)
			}
			return
		}

		// Token is valid, proceed
		next.ServeHTTP(w, r)
	})
}
