package handlers

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"

	"github.com/kms/api-key-service/internal/domain"
	"github.com/kms/api-key-service/internal/services"
)

// AuthHandler handles authentication-related HTTP requests
type AuthHandler struct {
	authService  services.AuthenticationService
	tokenService services.TokenService
	logger       *zap.Logger
}

// NewAuthHandler creates a new auth handler
func NewAuthHandler(
	authService services.AuthenticationService,
	tokenService services.TokenService,
	logger *zap.Logger,
) *AuthHandler {
	return &AuthHandler{
		authService:  authService,
		tokenService: tokenService,
		logger:       logger,
	}
}

// Login handles POST /login
func (h *AuthHandler) Login(c *gin.Context) {
	var req domain.LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		h.logger.Warn("Invalid login request", zap.Error(err))
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Invalid request body: " + err.Error(),
		})
		return
	}

	// For now, we'll extract user ID from headers since we're using HeaderAuthenticationProvider
	userID := c.GetHeader("X-User-Email")
	if userID == "" {
		h.logger.Warn("User email not found in headers")
		c.JSON(http.StatusUnauthorized, gin.H{
			"error":   "Unauthorized",
			"message": "User authentication required",
		})
		return
	}

	h.logger.Info("Processing login request", zap.String("user_id", userID), zap.String("app_id", req.AppID))

	// Generate user token
	token, err := h.tokenService.GenerateUserToken(c.Request.Context(), req.AppID, userID, req.Permissions)
	if err != nil {
		h.logger.Error("Failed to generate user token", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Internal Server Error",
			"message": "Failed to generate token",
		})
		return
	}

	// For now, we'll just return the token directly
	// In a real implementation, this would redirect to the callback URL
	response := domain.LoginResponse{
		RedirectURL: req.RedirectURI + "?token=" + token,
	}

	if req.RedirectURI == "" {
		// If no redirect URI, return token directly
		c.JSON(http.StatusOK, gin.H{
			"token":      token,
			"user_id":    userID,
			"app_id":     req.AppID,
			"expires_in": 604800, // 7 days in seconds
		})
		return
	}

	c.JSON(http.StatusOK, response)
}

// Verify handles POST /verify
func (h *AuthHandler) Verify(c *gin.Context) {
	var req domain.VerifyRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		h.logger.Warn("Invalid verify request", zap.Error(err))
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Invalid request body: " + err.Error(),
		})
		return
	}

	h.logger.Debug("Verifying token", zap.String("app_id", req.AppID), zap.String("type", string(req.Type)))

	response, err := h.tokenService.VerifyToken(c.Request.Context(), &req)
	if err != nil {
		h.logger.Error("Failed to verify token", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Internal Server Error",
			"message": "Failed to verify token",
		})
		return
	}

	c.JSON(http.StatusOK, response)
}

// Renew handles POST /renew
func (h *AuthHandler) Renew(c *gin.Context) {
	var req domain.RenewRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		h.logger.Warn("Invalid renew request", zap.Error(err))
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Invalid request body: " + err.Error(),
		})
		return
	}

	h.logger.Info("Renewing token", zap.String("app_id", req.AppID), zap.String("user_id", req.UserID))

	response, err := h.tokenService.RenewUserToken(c.Request.Context(), &req)
	if err != nil {
		h.logger.Error("Failed to renew token", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Internal Server Error",
			"message": "Failed to renew token",
		})
		return
	}

	c.JSON(http.StatusOK, response)
}
