package auth

import (
	"context"
	"errors"
)

var (
	// ErrInvalidAPIKey is returned when the API key is invalid.
	ErrInvalidAPIKey = errors.New("invalid API key")
)

// APIKeyLookup is a function that looks up a user by API key.
// Returns nil user and no error if the key is not found.
type APIKeyLookup func(ctx context.Context, key string) (*User, error)

// APIKeyValidator validates API keys using a lookup function.
type APIKeyValidator struct {
	lookup APIKeyLookup
}

// NewAPIKeyValidator creates a new API key validator.
//
// Example with database lookup:
//
//	validator := auth.NewAPIKeyValidator(func(ctx context.Context, key string) (*auth.User, error) {
//	    apiKey, err := db.GetAPIKeyByHash(ctx, hashKey(key))
//	    if err != nil {
//	        return nil, err
//	    }
//	    if apiKey == nil {
//	        return nil, nil // Key not found
//	    }
//	    return &auth.User{
//	        ID:     apiKey.UserID,
//	        Scopes: apiKey.Scopes,
//	    }, nil
//	})
func NewAPIKeyValidator(lookup APIKeyLookup) *APIKeyValidator {
	return &APIKeyValidator{lookup: lookup}
}

// Validate validates an API key and returns the associated user.
func (v *APIKeyValidator) Validate(ctx context.Context, key string) (*User, error) {
	if key == "" {
		return nil, ErrInvalidAPIKey
	}

	user, err := v.lookup(ctx, key)
	if err != nil {
		return nil, err
	}
	if user == nil {
		return nil, ErrInvalidAPIKey
	}

	return user, nil
}

// StaticAPIKeyValidator validates against a static set of API keys.
// Useful for simple use cases or testing.
type StaticAPIKeyValidator struct {
	keys map[string]*User
}

// NewStaticAPIKeyValidator creates a validator with static API keys.
//
// Example:
//
//	validator := auth.NewStaticAPIKeyValidator(map[string]*auth.User{
//	    "sk-test-123": {ID: "user-1", Scopes: []string{"read", "write"}},
//	    "sk-test-456": {ID: "user-2", Scopes: []string{"read"}},
//	})
func NewStaticAPIKeyValidator(keys map[string]*User) *StaticAPIKeyValidator {
	return &StaticAPIKeyValidator{keys: keys}
}

// Validate validates an API key against the static key map.
func (v *StaticAPIKeyValidator) Validate(ctx context.Context, key string) (*User, error) {
	if key == "" {
		return nil, ErrInvalidAPIKey
	}

	user, ok := v.keys[key]
	if !ok {
		return nil, ErrInvalidAPIKey
	}

	return user, nil
}
