package config

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/joho/godotenv"
)

type Environment string

const (
	Development Environment = "development"
	Staging     Environment = "staging"
	Production  Environment = "production"
)

type Config struct {
	Environment Environment
	DatabaseURL string
	JWTSecret   string
	Port        string
	MetricsPort string
	GinMode     string
	LogLevel    string
	Debug       bool
	LogDir      string
	LogVolume   string
}

// LoadConfig loads configuration with proper environment file precedence
func LoadConfig() *Config {
	// Load environment files in priority order
	loadEnvironmentFiles()

	// Get environment
	env := getEnvironment()

	// Load configuration
	config := &Config{
		Environment: env,
		DatabaseURL: getEnv("DATABASE_URL", getDefaultDatabaseURL(env)),
		JWTSecret:   getRequiredEnv("JWT_SECRET"),
		Port:        getEnv("PORT", "8080"),
		MetricsPort: getEnv("METRICS_PORT", "9090"),
		GinMode:     getGinMode(env),
		LogLevel:    getLogLevel(env),
		Debug:       env == Development,
		LogDir:      getEnv("LOG_DIR", "/app/logs"),
		LogVolume:   getEnv("LOG_VOLUME", "counter_logs"),
	}

	// Log configuration (without sensitive data)
	logConfig(config)

	return config
}

// loadEnvironmentFiles loads environment files in priority order
func loadEnvironmentFiles() {
	// Get environment first (from system env or default)
	env := getEnvironmentFromSystem()

	log.Printf("🔍 Detected environment: %s", env)

	// Define file loading order (later files override earlier ones)
	files := []string{
		".env",                      // Base configuration
		fmt.Sprintf(".env.%s", env), // Environment-specific
	}

	// Load files in order
	for _, file := range files {
		if _, err := os.Stat(file); err == nil {
			if err := godotenv.Load(file); err != nil {
				log.Printf("⚠️  Warning: Could not load %s: %v", file, err)
			} else {
				log.Printf("✅ Loaded: %s", file)
			}
		} else {
			log.Printf("❌ Not found: %s", file)
		}
	}
}

// getEnvironmentFromSystem gets environment from system variables only
func getEnvironmentFromSystem() string {
	// Check if ENVIRONMENT is already set
	if env := os.Getenv("ENVIRONMENT"); env != "" {
		return strings.ToLower(env)
	}

	// Fallback detection
	if ginMode := os.Getenv("GIN_MODE"); ginMode == "release" {
		return "production"
	}

	return "development"
}

// getEnvironment gets the current environment
func getEnvironment() Environment {
	env := strings.ToLower(getEnv("ENVIRONMENT", "development"))

	switch env {
	case "development", "dev":
		return Development
	case "staging", "stage":
		return Staging
	case "production", "prod":
		return Production
	default:
		log.Printf("⚠️  Unknown environment '%s', defaulting to development", env)
		return Development
	}
}

// getGinMode returns the appropriate Gin mode for the environment
func getGinMode(env Environment) string {
	switch env {
	case Production, Staging:
		return "release"
	case Development:
		return "debug"
	default:
		return "debug"
	}
}

// getLogLevel returns the appropriate log level for the environment
func getLogLevel(env Environment) string {
	switch env {
	case Production:
		return "info" // Changed from "warn" to "info" to capture more logs
	case Staging:
		return "info"
	case Development:
		return "debug"
	default:
		return "debug"
	}
}

// getDefaultDatabaseURL returns default database URL for environment
func getDefaultDatabaseURL(env Environment) string {
	switch env {
	case Development:
		return "postgres://postgres:password@localhost:5432/counter_db?sslmode=disable"
	case Staging:
		return "postgres://postgres:password@postgres:5432/counter_db?sslmode=disable"
	case Production:
		return "postgres://postgres:password@postgres:5432/counter_db?sslmode=require"
	default:
		return "postgres://postgres:password@localhost:5432/counter_db?sslmode=disable"
	}
}

// getEnv gets environment variable with default value
func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

// getRequiredEnv gets required environment variable
func getRequiredEnv(key string) string {
	value := os.Getenv(key)
	if value == "" {
		log.Fatalf("❌ Required environment variable %s is not set", key)
	}
	return value
}

// logConfig logs configuration (without sensitive data)
func logConfig(config *Config) {
	// Use standard log for configuration banner since logger might not be initialized yet
	log.Printf("")
	log.Printf("╔══════════════════════════════════════════════════════════════╗")
	log.Printf("║                    COUNTER APPLICATION                      ║")
	log.Printf("║                                                              ║")
	log.Printf("║  🌍 ENVIRONMENT: %-15s                              ║", strings.ToUpper(string(config.Environment)))
	log.Printf("║  🚀 MODE: %-20s                              ║", config.GinMode)
	log.Printf("║  🔧 DEBUG: %-20s                              ║", fmt.Sprintf("%t", config.Debug))
	log.Printf("║  📊 LOG LEVEL: %-15s                              ║", config.LogLevel)
	log.Printf("║  🌐 PORT: %-20s                              ║", config.Port)
	log.Printf("║  📈 METRICS PORT: %-15s                              ║", config.MetricsPort)
	log.Printf("║  📝 LOG DIR: %-20s                              ║", config.LogDir)
	log.Printf("║  📦 LOG VOLUME: %-18s                              ║", config.LogVolume)
	log.Printf("║                                                              ║")
	log.Printf("║  📁 Configuration Files Loaded:                              ║")
	log.Printf("║     • .env (base configuration)                              ║")
	log.Printf("║     • .env.%s (environment-specific)                     ║", config.Environment)
	log.Printf("║                                                              ║")
	log.Printf("║  🔐 Security:                                                ║")
	log.Printf("║     • Database: %s ║", maskDatabaseURL(config.DatabaseURL))
	log.Printf("║     • JWT Secret: %s ║", maskSecret(config.JWTSecret))
	log.Printf("║                                                              ║")
	log.Printf("╚══════════════════════════════════════════════════════════════╝")
	log.Printf("")
}

// maskDatabaseURL masks sensitive parts of database URL
func maskDatabaseURL(url string) string {
	// Simple masking - replace password with ***
	if strings.Contains(url, "://") {
		parts := strings.Split(url, "://")
		if len(parts) == 2 {
			// Replace password in connection string
			masked := strings.Replace(parts[1], ":", ":***@", 1)
			return parts[0] + "://" + masked
		}
	}
	return "***"
}

// maskSecret masks JWT secret for logging
func maskSecret(secret string) string {
	if len(secret) <= 8 {
		return "***"
	}
	return secret[:4] + "***" + secret[len(secret)-4:]
}
