package domain

import (
	"fmt"
	"regexp"
)

// PreferenceKey is a typed key for a known preference.
type PreferenceKey string

const (
	KeyTheme                PreferenceKey = "theme"
	KeyLanguage             PreferenceKey = "language"
	KeyNotificationsEnabled PreferenceKey = "notifications_enabled"
)

// PreferenceDefinition describes a known preference key with its default and validator.
type PreferenceDefinition struct {
	Key          PreferenceKey
	DefaultValue string
	Validate     func(value string) error
}

// UserPreferences is the aggregate representing all preferences for a user.
type UserPreferences struct {
	UserID      string
	Preferences map[PreferenceKey]string
}

// uuidRegex validates UUID format.
var uuidRegex = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)

// bcp47Regex validates BCP 47 language tags.
var bcp47Regex = regexp.MustCompile(`^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{1,8})*$`)

// validThemes is the set of allowed theme values.
var validThemes = map[string]bool{
	"light":  true,
	"dark":   true,
	"system": true,
}

// registry holds the definitions for all known preference keys.
var registry = map[PreferenceKey]PreferenceDefinition{
	KeyTheme: {
		Key:          KeyTheme,
		DefaultValue: "system",
		Validate: func(value string) error {
			if !validThemes[value] {
				return fmt.Errorf("%w: theme must be one of: light, dark, system", ErrInvalidPreferenceValue)
			}
			return nil
		},
	},
	KeyLanguage: {
		Key:          KeyLanguage,
		DefaultValue: "en",
		Validate: func(value string) error {
			if !bcp47Regex.MatchString(value) {
				return fmt.Errorf("%w: language must be a valid BCP 47 tag", ErrInvalidPreferenceValue)
			}
			return nil
		},
	},
	KeyNotificationsEnabled: {
		Key:          KeyNotificationsEnabled,
		DefaultValue: "true",
		Validate: func(value string) error {
			if value != "true" && value != "false" {
				return fmt.Errorf("%w: notifications_enabled must be true or false", ErrInvalidPreferenceValue)
			}
			return nil
		},
	},
}

// ValidateUserID checks that userID is a valid UUID.
func ValidateUserID(userID string) error {
	if !uuidRegex.MatchString(userID) {
		return ErrInvalidUserID
	}
	return nil
}

// ValidateKey checks that key is a known preference key.
func ValidateKey(key string) error {
	if _, ok := registry[PreferenceKey(key)]; !ok {
		return fmt.Errorf("%w: %s", ErrUnknownPreferenceKey, key)
	}
	return nil
}

// ValidateValue validates a value for the given preference key.
func ValidateValue(key PreferenceKey, value string) error {
	def, ok := registry[key]
	if !ok {
		return fmt.Errorf("%w: %s", ErrUnknownPreferenceKey, key)
	}
	return def.Validate(value)
}

// DefaultPreferences returns all known keys with their default values.
func DefaultPreferences() map[PreferenceKey]string {
	defaults := make(map[PreferenceKey]string, len(registry))
	for k, def := range registry {
		defaults[k] = def.DefaultValue
	}
	return defaults
}

// MergeWithDefaults fills in missing keys from defaults, preserving stored values.
func MergeWithDefaults(stored map[PreferenceKey]string) map[PreferenceKey]string {
	merged := DefaultPreferences()
	for k, v := range stored {
		merged[k] = v
	}
	return merged
}

// SerializeForResponse converts stored string values to typed values for JSON.
// notifications_enabled "true"/"false" becomes boolean true/false.
func SerializeForResponse(prefs map[PreferenceKey]string) map[string]any {
	result := make(map[string]any, len(prefs))
	for k, v := range prefs {
		switch k {
		case KeyNotificationsEnabled:
			result[string(k)] = v == "true"
		default:
			result[string(k)] = v
		}
	}
	return result
}
