package apikey

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"strings"
)

const (
	// PrefixLive is the prefix for production API keys
	PrefixLive = "live_sk_"
	// PrefixTest is the prefix for test/sandbox API keys
	PrefixTest = "test_sk_"
	// KeyLength is the length of the random part (40 chars in base64url)
	KeyLength = 30 // 30 bytes = 40 base64url chars
)

// Generator generates API keys
type Generator interface {
	// Generate creates a new live API key
	Generate() (string, error)
	// GenerateTest creates a new test API key
	GenerateTest() (string, error)
}

type generator struct{}

// NewGenerator creates a new API key generator
func NewGenerator() Generator {
	return &generator{}
}

// Generate creates a new live API key
func (g *generator) Generate() (string, error) {
	return g.generateWithPrefix(PrefixLive)
}

// GenerateTest creates a new test API key
func (g *generator) GenerateTest() (string, error) {
	return g.generateWithPrefix(PrefixTest)
}

func (g *generator) generateWithPrefix(prefix string) (string, error) {
	// Generate cryptographically secure random bytes
	b := make([]byte, KeyLength)
	if _, err := rand.Read(b); err != nil {
		return "", fmt.Errorf("failed to generate random bytes: %w", err)
	}

	// Encode to base64url (URL-safe, no padding)
	key := base64.RawURLEncoding.EncodeToString(b)

	// Remove any special chars and make lowercase for consistency
	key = strings.Map(func(r rune) rune {
		if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') {
			return r
		}
		return -1 // Remove character
	}, key)

	// Ensure we have at least 40 characters
	if len(key) < 40 {
		// Pad with additional random bytes if needed
		additional := make([]byte, 10)
		rand.Read(additional)
		extraKey := base64.RawURLEncoding.EncodeToString(additional)
		key += extraKey
	}

	// Trim to exactly 40 characters
	key = key[:40]

	return prefix + key, nil
}

// ExtractPrefix extracts the prefix from an API key
func ExtractPrefix(apiKey string) string {
	if len(apiKey) < 13 {
		return ""
	}
	return apiKey[:13] // "live_sk_a1b2" or "test_sk_a1b2"
}

// ExtractLastFour extracts the last 4 characters from an API key
func ExtractLastFour(apiKey string) string {
	if len(apiKey) < 4 {
		return ""
	}
	return apiKey[len(apiKey)-4:]
}

// IsValid checks if an API key has a valid format
func IsValid(apiKey string) bool {
	return strings.HasPrefix(apiKey, PrefixLive) || strings.HasPrefix(apiKey, PrefixTest)
}
