package auth

import (
	"context"
	"fmt"
	"time"

	"github.com/orchard9/rdev/internal/domain"
	"github.com/orchard9/rdev/internal/service"
)

// APIKey is an alias for domain.APIKey.
// All API key behavior (IsExpired, IsRevoked, etc.) lives in domain/apikey.go.
type APIKey = domain.APIKey

// Error sentinels — delegate to domain errors.
// Consumers should migrate to domain.ErrXxx over time.
var (
	ErrKeyNotFound  = domain.ErrKeyNotFound
	ErrKeyRevoked   = domain.ErrKeyRevoked
	ErrKeyExpired   = domain.ErrKeyExpired
	ErrIPNotAllowed = domain.ErrIPNotAllowed
)

// CreateKeyRequest is the input for creating a new key.
type CreateKeyRequest struct {
	Name       string
	Scopes     []Scope
	ProjectIDs []string      // nil = all projects
	AllowedIPs []string      // CIDR notation; nil = no restriction
	ExpiresIn  time.Duration // 0 = never
	CreatedBy  string
}

// CreateKeyResponse is the output of creating a new key.
type CreateKeyResponse struct {
	Key    *APIKey
	Secret string // Full key, shown only once
}

// Service handles API key operations.
// It wraps service.APIKeyService to provide the same interface as before
// while delegating to the hexagonal service layer.
type Service struct {
	svc      *service.APIKeyService
	adminKey string
}

// NewService creates a new auth service.
// Accepts a service.APIKeyService (hexagonal) instead of raw *sql.DB.
func NewService(svc *service.APIKeyService, adminKey string) *Service {
	return &Service{
		svc:      svc,
		adminKey: adminKey,
	}
}

// IsAdminKey checks if the provided key is the super admin key.
func (s *Service) IsAdminKey(key string) bool {
	return s.adminKey != "" && key == s.adminKey
}

// Create generates a new API key.
func (s *Service) Create(ctx context.Context, req CreateKeyRequest) (*CreateKeyResponse, error) {
	// Validate scopes
	if !ValidateScopes(req.Scopes) {
		return nil, fmt.Errorf("invalid scopes")
	}

	// Convert []string ProjectIDs to []domain.ProjectID
	var projectIDs []domain.ProjectID
	if req.ProjectIDs != nil {
		projectIDs = make([]domain.ProjectID, len(req.ProjectIDs))
		for i, p := range req.ProjectIDs {
			projectIDs[i] = domain.ProjectID(p)
		}
	}

	result, err := s.svc.Create(ctx, service.CreateKeyRequest{
		Name:       req.Name,
		Scopes:     req.Scopes,
		ProjectIDs: projectIDs,
		AllowedIPs: req.AllowedIPs,
		ExpiresIn:  req.ExpiresIn,
		CreatedBy:  req.CreatedBy,
	})
	if err != nil {
		return nil, err
	}

	return &CreateKeyResponse{
		Key:    result.Key,
		Secret: result.Secret,
	}, nil
}

// Validate checks if a key is valid and returns the key details.
func (s *Service) Validate(ctx context.Context, key string) (*APIKey, error) {
	return s.svc.Validate(ctx, key)
}

// List returns all API keys (without secrets).
func (s *Service) List(ctx context.Context) ([]*APIKey, error) {
	return s.svc.List(ctx)
}

// Get returns a single API key by ID.
func (s *Service) Get(ctx context.Context, id string) (*APIKey, error) {
	return s.svc.Get(ctx, domain.APIKeyID(id))
}

// Revoke marks an API key as revoked.
func (s *Service) Revoke(ctx context.Context, id string) error {
	return s.svc.Revoke(ctx, domain.APIKeyID(id))
}
