package auth

import (
	"context"
	"errors"
	"tercul/internal/domain"
	"tercul/internal/platform/auth"
	"tercul/internal/platform/log"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/trace"
)

var (
	ErrUserNotFound    = errors.New("user not found")
	ErrContextRequired = errors.New("context is required")
)

// AuthQueries contains the query handlers for authentication.
type AuthQueries struct {
	userRepo   domain.UserRepository
	jwtManager auth.JWTManagement
	tracer     trace.Tracer
}

// NewAuthQueries creates a new AuthQueries handler.
func NewAuthQueries(userRepo domain.UserRepository, jwtManager auth.JWTManagement) *AuthQueries {
	return &AuthQueries{
		userRepo:   userRepo,
		jwtManager: jwtManager,
		tracer:     otel.Tracer("auth.queries"),
	}
}

// GetUserFromContext extracts user from context
func (q *AuthQueries) GetUserFromContext(ctx context.Context) (*domain.User, error) {
	if ctx == nil {
		return nil, ErrContextRequired
	}
	ctx, span := q.tracer.Start(ctx, "GetUserFromContext")
	defer span.End()
	logger := log.FromContext(ctx)
	logger.Debug("Attempting to get user from context")

	claims, err := auth.RequireAuth(ctx)
	if err != nil {
		logger.Warn("Failed to get user from context - authentication required")
		return nil, err
	}
	logger = logger.With("user_id", claims.UserID)
	logger.Debug("Claims found in context")

	user, err := q.userRepo.GetByID(ctx, claims.UserID)
	if err != nil {
		logger.Warn("Failed to get user from context - user not found")
		return nil, ErrUserNotFound
	}

	if !user.Active {
		logger.Warn("Failed to get user from context - user inactive")
		return nil, ErrInvalidCredentials
	}

	logger.Debug("User retrieved from context successfully")
	return user, nil
}

// ValidateToken validates a JWT token and returns the user
func (q *AuthQueries) ValidateToken(ctx context.Context, tokenString string) (*domain.User, error) {
	if ctx == nil {
		return nil, ErrContextRequired
	}
	ctx, span := q.tracer.Start(ctx, "ValidateToken")
	defer span.End()
	logger := log.FromContext(ctx)

	if tokenString == "" {
		logger.Warn("Token validation failed - empty token")
		return nil, auth.ErrMissingToken
	}
	logger.Debug("Attempting to validate token")

	claims, err := q.jwtManager.ValidateToken(tokenString)
	if err != nil {
		logger.Error(err, "Token validation failed - invalid token")
		return nil, err
	}

	logger = logger.With("user_id", claims.UserID)
	logger.Debug("Token claims validated")

	user, err := q.userRepo.GetByID(ctx, claims.UserID)
	if err != nil {
		logger.Error(err, "Token validation failed - user not found")
		return nil, ErrUserNotFound
	}

	if !user.Active {
		logger.Warn("Token validation failed - user inactive")
		return nil, ErrInvalidCredentials
	}

	logger.Info("Token validated successfully")
	return user, nil
}
