package config

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/spf13/viper"
)

// Config holds all application configuration
type Config struct {
	Server   ServerConfig   `mapstructure:"server"`
	Database DatabaseConfig `mapstructure:"database"`
	App      AppConfig      `mapstructure:"app"`
	Security SecurityConfig `mapstructure:"security"`
	Logging  LoggingConfig  `mapstructure:"logging"`
	External ExternalConfig `mapstructure:"external_services"`
	Features FeatureConfig  `mapstructure:"features"`
	Defaults DefaultConfig  `mapstructure:"defaults"`
}

// ServerConfig holds server-related configuration
type ServerConfig struct {
	Host            string        `mapstructure:"host"`
	Port            int           `mapstructure:"port"`
	ReadTimeout     time.Duration `mapstructure:"read_timeout"`
	WriteTimeout    time.Duration `mapstructure:"write_timeout"`
	IdleTimeout     time.Duration `mapstructure:"idle_timeout"`
	ShutdownTimeout time.Duration `mapstructure:"shutdown_timeout"`
}

// DatabaseConfig holds database-related configuration
type DatabaseConfig struct {
	Path           string                    `mapstructure:"path"`
	ConnectionPool DatabaseConnectionConfig  `mapstructure:"connection_pool"`
	Logging        DatabaseLoggingConfig     `mapstructure:"logging"`
	Migration      DatabaseMigrationConfig   `mapstructure:"migration"`
	Performance    DatabasePerformanceConfig `mapstructure:"performance"`
}

// DatabaseConnectionConfig holds database connection pool settings
type DatabaseConnectionConfig struct {
	MaxIdleConnections    int           `mapstructure:"max_idle_connections"`
	MaxOpenConnections    int           `mapstructure:"max_open_connections"`
	ConnectionMaxLifetime time.Duration `mapstructure:"connection_max_lifetime"`
	ConnectionMaxIdleTime time.Duration `mapstructure:"connection_max_idle_time"`
}

// DatabaseLoggingConfig holds database logging settings
type DatabaseLoggingConfig struct {
	Level              string        `mapstructure:"level"`
	SlowQueryThreshold time.Duration `mapstructure:"slow_query_threshold"`
	Debug              bool          `mapstructure:"debug"`
}

// DatabaseMigrationConfig holds database migration settings
type DatabaseMigrationConfig struct {
	AutoMigrate     bool `mapstructure:"auto_migrate"`
	DropTablesFirst bool `mapstructure:"drop_tables_first"`
	CreateBatchSize int  `mapstructure:"create_batch_size"`
}

// DatabasePerformanceConfig holds database performance settings
type DatabasePerformanceConfig struct {
	PrepareStatements                bool `mapstructure:"prepare_statements"`
	DisableForeignKeyCheck           bool `mapstructure:"disable_foreign_key_check"`
	IgnoreRelationshipsWhenMigrating bool `mapstructure:"ignore_relationships_when_migrating"`
	QueryFields                      bool `mapstructure:"query_fields"`
	DryRun                           bool `mapstructure:"dry_run"`
	CreateInBatches                  int  `mapstructure:"create_in_batches"`
}

// AppConfig holds general application settings
type AppConfig struct {
	Name        string `mapstructure:"name"`
	Version     string `mapstructure:"version"`
	Environment string `mapstructure:"environment"`
	Debug       bool   `mapstructure:"debug"`
}

// SecurityConfig holds security-related settings
type SecurityConfig struct {
	Session  SessionConfig  `mapstructure:"session"`
	Password PasswordConfig `mapstructure:"password"`
}

// SessionConfig holds session management settings
type SessionConfig struct {
	Timeout       time.Duration `mapstructure:"timeout"`
	CookieName    string        `mapstructure:"cookie_name"`
	SecureCookies bool          `mapstructure:"secure_cookies"`
	HttpOnly      bool          `mapstructure:"http_only"`
}

// PasswordConfig holds password requirements
type PasswordConfig struct {
	MinLength           int  `mapstructure:"min_length"`
	RequireUppercase    bool `mapstructure:"require_uppercase"`
	RequireLowercase    bool `mapstructure:"require_lowercase"`
	RequireNumbers      bool `mapstructure:"require_numbers"`
	RequireSpecialChars bool `mapstructure:"require_special_chars"`
}

// LoggingConfig holds logging settings
type LoggingConfig struct {
	Level    string            `mapstructure:"level"`
	Format   string            `mapstructure:"format"`
	Output   string            `mapstructure:"output"`
	FilePath string            `mapstructure:"file_path"`
	Rotation LogRotationConfig `mapstructure:"rotation"`
}

// LogRotationConfig holds log rotation settings
type LogRotationConfig struct {
	Enabled    bool   `mapstructure:"enabled"`
	MaxSize    string `mapstructure:"max_size"`
	MaxAge     string `mapstructure:"max_age"`
	MaxBackups int    `mapstructure:"max_backups"`
}

// ExternalConfig holds external service configurations
type ExternalConfig struct {
	OverpassAPI OverpassAPIConfig `mapstructure:"overpass_api"`
}

// OverpassAPIConfig holds OpenStreetMap Overpass API settings
type OverpassAPIConfig struct {
	URL          string        `mapstructure:"url"`
	Timeout      time.Duration `mapstructure:"timeout"`
	MaxRetries   int           `mapstructure:"max_retries"`
	SearchRadius int           `mapstructure:"search_radius"`
}

// FeatureConfig holds feature flag settings
type FeatureConfig struct {
	FuelStationSearch   bool `mapstructure:"fuel_station_search"`
	VehicleManagement   bool `mapstructure:"vehicle_management"`
	StatisticsDashboard bool `mapstructure:"statistics_dashboard"`
	DataExport          bool `mapstructure:"data_export"`
	APIEndpoints        bool `mapstructure:"api_endpoints"`
}

// DefaultConfig holds default values for new entities
type DefaultConfig struct {
	Currency     string `mapstructure:"currency"`
	FuelType     string `mapstructure:"fuel_type"`
	DistanceUnit string `mapstructure:"distance_unit"`
	VolumeUnit   string `mapstructure:"volume_unit"`
}

// Load loads configuration from file, environment variables, and defaults
func Load(configPath string) (*Config, error) {
	v := viper.New()

	// Set defaults
	setDefaults(v)

	// Configure Viper
	if configPath != "" {
		v.SetConfigFile(configPath)
	} else {
		v.SetConfigName("config")
		v.SetConfigType("yaml")
		v.AddConfigPath(".")
		v.AddConfigPath("./config")
		v.AddConfigPath("$HOME/.tankstopp")
		v.AddConfigPath("/etc/tankstopp")
	}

	// Enable environment variable binding
	v.AutomaticEnv()
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	v.SetEnvPrefix("TANKSTOPP")

	// Read config file
	if err := v.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
			return nil, fmt.Errorf("error reading config file: %w", err)
		}
		// Config file not found, continue with defaults and env vars
	}

	// Unmarshal into struct
	var config Config
	if err := v.Unmarshal(&config); err != nil {
		return nil, fmt.Errorf("error unmarshaling config: %w", err)
	}

	// Validate configuration
	if err := config.Validate(); err != nil {
		return nil, fmt.Errorf("invalid configuration: %w", err)
	}

	return &config, nil
}

// setDefaults sets default values for configuration
func setDefaults(v *viper.Viper) {
	// Server defaults
	v.SetDefault("server.host", "localhost")
	v.SetDefault("server.port", 8081)
	v.SetDefault("server.read_timeout", "30s")
	v.SetDefault("server.write_timeout", "30s")
	v.SetDefault("server.idle_timeout", "120s")
	v.SetDefault("server.shutdown_timeout", "10s")

	// Database defaults
	v.SetDefault("database.path", "fuel_stops.db")
	v.SetDefault("database.connection_pool.max_idle_connections", 10)
	v.SetDefault("database.connection_pool.max_open_connections", 100)
	v.SetDefault("database.connection_pool.connection_max_lifetime", "1h")
	v.SetDefault("database.connection_pool.connection_max_idle_time", "30m")
	v.SetDefault("database.logging.level", "warn")
	v.SetDefault("database.logging.slow_query_threshold", "200ms")
	v.SetDefault("database.logging.debug", false)
	v.SetDefault("database.migration.auto_migrate", true)
	v.SetDefault("database.migration.drop_tables_first", false)
	v.SetDefault("database.migration.create_batch_size", 1000)
	v.SetDefault("database.performance.prepare_statements", true)
	v.SetDefault("database.performance.disable_foreign_key_check", false)
	v.SetDefault("database.performance.ignore_relationships_when_migrating", false)
	v.SetDefault("database.performance.query_fields", true)
	v.SetDefault("database.performance.dry_run", false)
	v.SetDefault("database.performance.create_in_batches", 100)

	// App defaults
	v.SetDefault("app.name", "TankStopp")
	v.SetDefault("app.version", "1.0.0")
	v.SetDefault("app.environment", "development")
	v.SetDefault("app.debug", true)

	// Security defaults
	v.SetDefault("security.session.timeout", "24h")
	v.SetDefault("security.session.cookie_name", "tankstopp_session")
	v.SetDefault("security.session.secure_cookies", false)
	v.SetDefault("security.session.http_only", true)
	v.SetDefault("security.password.min_length", 8)
	v.SetDefault("security.password.require_uppercase", true)
	v.SetDefault("security.password.require_lowercase", true)
	v.SetDefault("security.password.require_numbers", true)
	v.SetDefault("security.password.require_special_chars", false)

	// Logging defaults
	v.SetDefault("logging.level", "info")
	v.SetDefault("logging.format", "text")
	v.SetDefault("logging.output", "stdout")
	v.SetDefault("logging.file_path", "logs/tankstopp.log")
	v.SetDefault("logging.rotation.enabled", false)
	v.SetDefault("logging.rotation.max_size", "100MB")
	v.SetDefault("logging.rotation.max_age", "30d")
	v.SetDefault("logging.rotation.max_backups", 5)

	// External services defaults
	v.SetDefault("external_services.overpass_api.url", "https://overpass-api.de/api/interpreter")
	v.SetDefault("external_services.overpass_api.timeout", "30s")
	v.SetDefault("external_services.overpass_api.max_retries", 3)
	v.SetDefault("external_services.overpass_api.search_radius", 5000)

	// Feature flags defaults
	v.SetDefault("features.fuel_station_search", true)
	v.SetDefault("features.vehicle_management", true)
	v.SetDefault("features.statistics_dashboard", true)
	v.SetDefault("features.data_export", true)
	v.SetDefault("features.api_endpoints", true)

	// Default values
	v.SetDefault("defaults.currency", "EUR")
	v.SetDefault("defaults.fuel_type", "Super E5")
	v.SetDefault("defaults.distance_unit", "km")
	v.SetDefault("defaults.volume_unit", "liters")
}

// Validate validates the configuration
func (c *Config) Validate() error {
	// Validate server config
	if c.Server.Port < 1 || c.Server.Port > 65535 {
		return fmt.Errorf("invalid server port: %d", c.Server.Port)
	}

	// Validate database config
	if c.Database.Path == "" {
		return fmt.Errorf("database path cannot be empty")
	}

	if c.Database.ConnectionPool.MaxIdleConnections < 0 {
		return fmt.Errorf("max idle connections cannot be negative")
	}

	if c.Database.ConnectionPool.MaxOpenConnections < 0 {
		return fmt.Errorf("max open connections cannot be negative")
	}

	// Validate app config
	if c.App.Name == "" {
		return fmt.Errorf("app name cannot be empty")
	}

	validEnvs := []string{"development", "production", "test"}
	if !contains(validEnvs, c.App.Environment) {
		return fmt.Errorf("invalid environment: %s (must be one of: %v)", c.App.Environment, validEnvs)
	}

	// Validate security config
	if c.Security.Password.MinLength < 4 {
		return fmt.Errorf("minimum password length cannot be less than 4")
	}

	// Validate logging config
	validLogLevels := []string{"debug", "info", "warn", "error"}
	if !contains(validLogLevels, c.Logging.Level) {
		return fmt.Errorf("invalid log level: %s (must be one of: %v)", c.Logging.Level, validLogLevels)
	}

	validLogFormats := []string{"json", "text"}
	if !contains(validLogFormats, c.Logging.Format) {
		return fmt.Errorf("invalid log format: %s (must be one of: %v)", c.Logging.Format, validLogFormats)
	}

	return nil
}

// IsProduction returns true if the app is running in production environment
func (c *Config) IsProduction() bool {
	return c.App.Environment == "production"
}

// IsDevelopment returns true if the app is running in development environment
func (c *Config) IsDevelopment() bool {
	return c.App.Environment == "development"
}

// IsTest returns true if the app is running in test environment
func (c *Config) IsTest() bool {
	return c.App.Environment == "test"
}

// GetServerAddress returns the server address in host:port format
func (c *Config) GetServerAddress() string {
	return fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port)
}

// String returns a string representation of the configuration (without sensitive data)
func (c *Config) String() string {
	return fmt.Sprintf(`TankStopp Configuration:
  Server: %s
  Database: %s
  Environment: %s
  Debug: %t
  Features: %+v`,
		c.GetServerAddress(),
		c.Database.Path,
		c.App.Environment,
		c.App.Debug,
		c.Features)
}

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

// GetConfigFromEnv returns environment-specific configuration
func GetConfigFromEnv() string {
	if configPath := os.Getenv("TANKSTOPP_CONFIG_PATH"); configPath != "" {
		return configPath
	}

	env := os.Getenv("TANKSTOPP_ENV")
	if env == "" {
		env = os.Getenv("ENV")
	}
	if env == "" {
		env = "development"
	}

	return fmt.Sprintf("config.%s.yaml", env)
}
