package handlers

import (
	"net/http"
	"strconv"

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

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

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

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

// Create handles POST /applications/:id/tokens
func (h *TokenHandler) Create(c *gin.Context) {
	appID := c.Param("id")
	if appID == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Application ID is required",
		})
		return
	}

	var req domain.CreateStaticTokenRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		h.logger.Warn("Invalid request body", zap.Error(err))
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Invalid request body: " + err.Error(),
		})
		return
	}

	// Set app ID from URL parameter
	req.AppID = appID

	// Get user ID from context
	userID, exists := c.Get("user_id")
	if !exists {
		h.logger.Error("User ID not found in context")
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Internal Server Error",
			"message": "Authentication context not found",
		})
		return
	}

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

	h.logger.Info("Token created", zap.String("token_id", token.ID.String()))
	c.JSON(http.StatusCreated, token)
}

// ListByApp handles GET /applications/:id/tokens
func (h *TokenHandler) ListByApp(c *gin.Context) {
	appID := c.Param("id")
	if appID == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Application ID is required",
		})
		return
	}

	// Parse pagination parameters
	limit := 50
	offset := 0

	if l := c.Query("limit"); l != "" {
		if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
			limit = parsed
		}
	}

	if o := c.Query("offset"); o != "" {
		if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
			offset = parsed
		}
	}

	tokens, err := h.tokenService.ListByApp(c.Request.Context(), appID, limit, offset)
	if err != nil {
		h.logger.Error("Failed to list tokens", zap.Error(err), zap.String("app_id", appID))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Internal Server Error",
			"message": "Failed to list tokens",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"data":   tokens,
		"limit":  limit,
		"offset": offset,
		"count":  len(tokens),
	})
}

// Delete handles DELETE /tokens/:id
func (h *TokenHandler) Delete(c *gin.Context) {
	tokenIDStr := c.Param("id")
	if tokenIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Token ID is required",
		})
		return
	}

	tokenID, err := uuid.Parse(tokenIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Bad Request",
			"message": "Invalid token ID format",
		})
		return
	}

	// Get user ID from context
	userID, exists := c.Get("user_id")
	if !exists {
		h.logger.Error("User ID not found in context")
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Internal Server Error",
			"message": "Authentication context not found",
		})
		return
	}

	err = h.tokenService.Delete(c.Request.Context(), tokenID, userID.(string))
	if err != nil {
		h.logger.Error("Failed to delete token", zap.Error(err), zap.String("token_id", tokenID.String()))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Internal Server Error",
			"message": "Failed to delete token",
		})
		return
	}

	h.logger.Info("Token deleted", zap.String("token_id", tokenID.String()))
	c.JSON(http.StatusNoContent, nil)
}
