package config

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

// HybridConfig manages feature flags and configuration for Phase 2 hybrid mode
type HybridConfig struct {
	// DHT Configuration
	DHT HybridDHTConfig `json:"dht" yaml:"dht"`
	
	// UCXL Configuration  
	UCXL HybridUCXLConfig `json:"ucxl" yaml:"ucxl"`
	
	// Discovery Configuration
	Discovery DiscoveryConfig `json:"discovery" yaml:"discovery"`
	
	// Monitoring Configuration
	Monitoring MonitoringConfig `json:"monitoring" yaml:"monitoring"`
}

type HybridDHTConfig struct {
	Backend             string        `env:"BZZZ_DHT_BACKEND" default:"mock" json:"backend" yaml:"backend"`
	BootstrapNodes      []string      `env:"BZZZ_DHT_BOOTSTRAP_NODES" json:"bootstrap_nodes" yaml:"bootstrap_nodes"`
	FallbackOnError     bool          `env:"BZZZ_FALLBACK_ON_ERROR" default:"true" json:"fallback_on_error" yaml:"fallback_on_error"`
	HealthCheckInterval time.Duration `env:"BZZZ_HEALTH_CHECK_INTERVAL" default:"30s" json:"health_check_interval" yaml:"health_check_interval"`
	MaxRetries          int           `env:"BZZZ_DHT_MAX_RETRIES" default:"3" json:"max_retries" yaml:"max_retries"`
	RetryBackoff        time.Duration `env:"BZZZ_DHT_RETRY_BACKOFF" default:"1s" json:"retry_backoff" yaml:"retry_backoff"`
	OperationTimeout    time.Duration `env:"BZZZ_DHT_OPERATION_TIMEOUT" default:"10s" json:"operation_timeout" yaml:"operation_timeout"`
}

type HybridUCXLConfig struct {
	CacheEnabled       bool          `env:"BZZZ_UCXL_CACHE_ENABLED" default:"true" json:"cache_enabled" yaml:"cache_enabled"`
	CacheTTL          time.Duration `env:"BZZZ_UCXL_CACHE_TTL" default:"5m" json:"cache_ttl" yaml:"cache_ttl"`
	UseDistributed    bool          `env:"BZZZ_UCXL_USE_DISTRIBUTED" default:"false" json:"use_distributed" yaml:"use_distributed"`
	MaxCacheSize      int           `env:"BZZZ_UCXL_MAX_CACHE_SIZE" default:"10000" json:"max_cache_size" yaml:"max_cache_size"`
}

type DiscoveryConfig struct {
	MDNSEnabled       bool          `env:"BZZZ_MDNS_ENABLED" default:"true" json:"mdns_enabled" yaml:"mdns_enabled"`
	DHTDiscovery      bool          `env:"BZZZ_DHT_DISCOVERY" default:"false" json:"dht_discovery" yaml:"dht_discovery"`
	AnnounceInterval  time.Duration `env:"BZZZ_ANNOUNCE_INTERVAL" default:"30s" json:"announce_interval" yaml:"announce_interval"`
	ServiceName       string        `env:"BZZZ_SERVICE_NAME" default:"bzzz" json:"service_name" yaml:"service_name"`
}

type MonitoringConfig struct {
	Enabled           bool          `env:"BZZZ_MONITORING_ENABLED" default:"true" json:"enabled" yaml:"enabled"`
	MetricsInterval   time.Duration `env:"BZZZ_METRICS_INTERVAL" default:"15s" json:"metrics_interval" yaml:"metrics_interval"`
	HealthEndpoint    string        `env:"BZZZ_HEALTH_ENDPOINT" default:"/health" json:"health_endpoint" yaml:"health_endpoint"`
	MetricsEndpoint   string        `env:"BZZZ_METRICS_ENDPOINT" default:"/metrics" json:"metrics_endpoint" yaml:"metrics_endpoint"`
}

// LoadHybridConfig loads configuration from environment variables with defaults
func LoadHybridConfig() (*HybridConfig, error) {
	config := &HybridConfig{}
	
	// Load DHT configuration
	config.DHT = HybridDHTConfig{
		Backend:             getEnvString("BZZZ_DHT_BACKEND", "mock"),
		BootstrapNodes:      getEnvStringSlice("BZZZ_DHT_BOOTSTRAP_NODES", []string{}),
		FallbackOnError:     getEnvBool("BZZZ_FALLBACK_ON_ERROR", true),
		HealthCheckInterval: getEnvDuration("BZZZ_HEALTH_CHECK_INTERVAL", 30*time.Second),
		MaxRetries:          getEnvInt("BZZZ_DHT_MAX_RETRIES", 3),
		RetryBackoff:        getEnvDuration("BZZZ_DHT_RETRY_BACKOFF", 1*time.Second),
		OperationTimeout:    getEnvDuration("BZZZ_DHT_OPERATION_TIMEOUT", 10*time.Second),
	}
	
	// Load UCXL configuration
	config.UCXL = HybridUCXLConfig{
		CacheEnabled:    getEnvBool("BZZZ_UCXL_CACHE_ENABLED", true),
		CacheTTL:        getEnvDuration("BZZZ_UCXL_CACHE_TTL", 5*time.Minute),
		UseDistributed:  getEnvBool("BZZZ_UCXL_USE_DISTRIBUTED", false),
		MaxCacheSize:    getEnvInt("BZZZ_UCXL_MAX_CACHE_SIZE", 10000),
	}
	
	// Load Discovery configuration
	config.Discovery = DiscoveryConfig{
		MDNSEnabled:      getEnvBool("BZZZ_MDNS_ENABLED", true),
		DHTDiscovery:     getEnvBool("BZZZ_DHT_DISCOVERY", false),
		AnnounceInterval: getEnvDuration("BZZZ_ANNOUNCE_INTERVAL", 30*time.Second),
		ServiceName:      getEnvString("BZZZ_SERVICE_NAME", "bzzz"),
	}
	
	// Load Monitoring configuration
	config.Monitoring = MonitoringConfig{
		Enabled:         getEnvBool("BZZZ_MONITORING_ENABLED", true),
		MetricsInterval: getEnvDuration("BZZZ_METRICS_INTERVAL", 15*time.Second),
		HealthEndpoint:  getEnvString("BZZZ_HEALTH_ENDPOINT", "/health"),
		MetricsEndpoint: getEnvString("BZZZ_METRICS_ENDPOINT", "/metrics"),
	}
	
	// Validate configuration
	if err := config.Validate(); err != nil {
		return nil, fmt.Errorf("invalid configuration: %w", err)
	}
	
	return config, nil
}

// Validate checks configuration values for correctness
func (c *HybridConfig) Validate() error {
	// Validate DHT backend
	validBackends := []string{"mock", "real", "hybrid"}
	if !hybridContains(validBackends, c.DHT.Backend) {
		return fmt.Errorf("invalid DHT backend '%s', must be one of: %v", c.DHT.Backend, validBackends)
	}
	
	// Validate timeouts
	if c.DHT.HealthCheckInterval < time.Second {
		return fmt.Errorf("health check interval too short: %v", c.DHT.HealthCheckInterval)
	}
	
	if c.DHT.OperationTimeout < 100*time.Millisecond {
		return fmt.Errorf("operation timeout too short: %v", c.DHT.OperationTimeout)
	}
	
	// Validate cache settings
	if c.UCXL.MaxCacheSize < 0 {
		return fmt.Errorf("max cache size must be non-negative: %d", c.UCXL.MaxCacheSize)
	}
	
	return nil
}

// IsRealDHTEnabled returns true if real DHT should be used
func (c *HybridConfig) IsRealDHTEnabled() bool {
	return c.DHT.Backend == "real" || c.DHT.Backend == "hybrid"
}

// IsMockDHTEnabled returns true if mock DHT should be used
func (c *HybridConfig) IsMockDHTEnabled() bool {
	return c.DHT.Backend == "mock" || c.DHT.Backend == "hybrid"
}

// IsFallbackEnabled returns true if fallback to mock is enabled
func (c *HybridConfig) IsFallbackEnabled() bool {
	return c.DHT.FallbackOnError && c.IsMockDHTEnabled()
}

// GetDHTBootstrapNodes returns the list of bootstrap nodes for real DHT
func (c *HybridConfig) GetDHTBootstrapNodes() []string {
	return c.DHT.BootstrapNodes
}

// Helper functions for environment variable parsing

func getEnvString(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

func getEnvBool(key string, defaultValue bool) bool {
	if value := os.Getenv(key); value != "" {
		parsed, err := strconv.ParseBool(value)
		if err == nil {
			return parsed
		}
	}
	return defaultValue
}

func getEnvInt(key string, defaultValue int) int {
	if value := os.Getenv(key); value != "" {
		parsed, err := strconv.Atoi(value)
		if err == nil {
			return parsed
		}
	}
	return defaultValue
}

func getEnvDuration(key string, defaultValue time.Duration) time.Duration {
	if value := os.Getenv(key); value != "" {
		parsed, err := time.ParseDuration(value)
		if err == nil {
			return parsed
		}
	}
	return defaultValue
}

func getEnvStringSlice(key string, defaultValue []string) []string {
	if value := os.Getenv(key); value != "" {
		return strings.Split(value, ",")
	}
	return defaultValue
}

func hybridContains(slice []string, item string) bool {
	for _, s := range slice {
		if s == item {
			return true
		}
	}
	return false
}

// ConfigurationChangeEvent represents a configuration update
type ConfigurationChangeEvent struct {
	Component string
	Old       interface{}
	New       interface{}
	Timestamp time.Time
}

// ConfigWatcher provides real-time configuration updates
type ConfigWatcher struct {
	events chan ConfigurationChangeEvent
	config *HybridConfig
}

// NewConfigWatcher creates a new configuration watcher
func NewConfigWatcher(config *HybridConfig) *ConfigWatcher {
	return &ConfigWatcher{
		events: make(chan ConfigurationChangeEvent, 100),
		config: config,
	}
}

// Events returns the configuration change events channel
func (w *ConfigWatcher) Events() <-chan ConfigurationChangeEvent {
	return w.events
}

// UpdateDHTBackend changes the DHT backend at runtime
func (w *ConfigWatcher) UpdateDHTBackend(backend string) error {
	validBackends := []string{"mock", "real", "hybrid"}
	if !hybridContains(validBackends, backend) {
		return fmt.Errorf("invalid DHT backend '%s'", backend)
	}
	
	old := w.config.DHT.Backend
	w.config.DHT.Backend = backend
	
	w.events <- ConfigurationChangeEvent{
		Component: "dht.backend",
		Old:       old,
		New:       backend,
		Timestamp: time.Now(),
	}
	
	return nil
}

// Close closes the configuration watcher
func (w *ConfigWatcher) Close() {
	close(w.events)
}