package handlers

import (
	"net/http"
	"strconv"

	"github.com/labstack/echo/v4"
	"gorm.io/gorm"

	"github.com/treytartt/honeydue-api/internal/admin/dto"
	"github.com/treytartt/honeydue-api/internal/models"
)

// AdminAuthTokenHandler handles admin auth token management endpoints
type AdminAuthTokenHandler struct {
	db *gorm.DB
}

// NewAdminAuthTokenHandler creates a new admin auth token handler
func NewAdminAuthTokenHandler(db *gorm.DB) *AdminAuthTokenHandler {
	return &AdminAuthTokenHandler{db: db}
}

// AuthTokenResponse represents an auth token in API responses
type AuthTokenResponse struct {
	Key      string `json:"key"`
	UserID   uint   `json:"user_id"`
	Username string `json:"username"`
	Email    string `json:"email"`
	Created  string `json:"created"`
}

// List handles GET /api/admin/auth-tokens
func (h *AdminAuthTokenHandler) List(c echo.Context) error {
	var filters dto.PaginationParams
	if err := c.Bind(&filters); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	var tokens []models.AuthToken
	var total int64

	query := h.db.Model(&models.AuthToken{}).Preload("User")

	// Apply search (search by user info)
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Joins("JOIN auth_user ON auth_user.id = user_authtoken.user_id").
			Where(
				"auth_user.username ILIKE ? OR auth_user.email ILIKE ? OR user_authtoken.key ILIKE ?",
				search, search, search,
			)
	}

	// Get total count
	query.Count(&total)

	// Apply sorting (allowlist prevents SQL injection via sort_by parameter)
	sortBy := filters.GetSafeSortBy([]string{
		"created", "user_id",
	}, "created")
	query = query.Order(sortBy + " " + filters.GetSortDir())

	// Apply pagination
	query = query.Offset(filters.GetOffset()).Limit(filters.GetPerPage())

	if err := query.Find(&tokens).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch auth tokens"})
	}

	// Build response
	responses := make([]AuthTokenResponse, len(tokens))
	for i, token := range tokens {
		responses[i] = AuthTokenResponse{
			Key:      token.Key,
			UserID:   token.UserID,
			Username: token.User.Username,
			Email:    token.User.Email,
			Created:  token.Created.Format("2006-01-02T15:04:05Z"),
		}
	}

	return c.JSON(http.StatusOK, dto.NewPaginatedResponse(responses, total, filters.GetPage(), filters.GetPerPage()))
}

// Get handles GET /api/admin/auth-tokens/:id (id is actually user_id)
func (h *AdminAuthTokenHandler) Get(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid user ID"})
	}

	var token models.AuthToken
	if err := h.db.Preload("User").Where("user_id = ?", id).First(&token).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Auth token not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch auth token"})
	}

	response := AuthTokenResponse{
		Key:      token.Key,
		UserID:   token.UserID,
		Username: token.User.Username,
		Email:    token.User.Email,
		Created:  token.Created.Format("2006-01-02T15:04:05Z"),
	}

	return c.JSON(http.StatusOK, response)
}

// Delete handles DELETE /api/admin/auth-tokens/:id (revoke token)
func (h *AdminAuthTokenHandler) Delete(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid user ID"})
	}

	result := h.db.Where("user_id = ?", id).Delete(&models.AuthToken{})
	if result.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to revoke token"})
	}

	if result.RowsAffected == 0 {
		return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Auth token not found"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Auth token revoked successfully"})
}

// BulkDelete handles DELETE /api/admin/auth-tokens/bulk
func (h *AdminAuthTokenHandler) BulkDelete(c echo.Context) error {
	var req dto.BulkDeleteRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	result := h.db.Where("user_id IN ?", req.IDs).Delete(&models.AuthToken{})
	if result.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to revoke tokens"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Auth tokens revoked successfully", "count": result.RowsAffected})
}
