package config

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

// Config holds the application configuration
type Config struct {
	Server struct {
		Host      string `env:"REDFLAG_SERVER_HOST" default:"0.0.0.0"`
		Port      int    `env:"REDFLAG_SERVER_PORT" default:"8080"`
		PublicURL string `env:"REDFLAG_PUBLIC_URL"` // Optional: External URL for reverse proxy/load balancer
		TLS       struct {
			Enabled  bool   `env:"REDFLAG_TLS_ENABLED" default:"false"`
			CertFile string `env:"REDFLAG_TLS_CERT_FILE"`
			KeyFile  string `env:"REDFLAG_TLS_KEY_FILE"`
		}
	}
	Database struct {
		Host     string `env:"REDFLAG_DB_HOST" default:"localhost"`
		Port     int    `env:"REDFLAG_DB_PORT" default:"5432"`
		Database string `env:"REDFLAG_DB_NAME" default:"redflag"`
		Username string `env:"REDFLAG_DB_USER" default:"redflag"`
		Password string `env:"REDFLAG_DB_PASSWORD"`
	}
	Admin struct {
		Username  string `env:"REDFLAG_ADMIN_USER" default:"admin"`
		Email     string `env:"REDFLAG_ADMIN_EMAIL" default:"admin@example.com"`
		Password  string `env:"REDFLAG_ADMIN_PASSWORD"`
		JWTSecret string `env:"REDFLAG_JWT_SECRET"`
	}
	AgentRegistration struct {
		TokenExpiry string `env:"REDFLAG_TOKEN_EXPIRY" default:"24h"`
		MaxTokens   int    `env:"REDFLAG_MAX_TOKENS" default:"100"`
		MaxSeats    int    `env:"REDFLAG_MAX_SEATS" default:"50"`
	}
	CheckInInterval    int
	OfflineThreshold   int
	Timezone           string
	LatestAgentVersion string
	MinAgentVersion    string `env:"MIN_AGENT_VERSION" default:"0.1.22"`
	SigningPrivateKey   string `env:"REDFLAG_SIGNING_PRIVATE_KEY"`
	BinaryStoragePath  string `env:"REDFLAG_BINARY_STORAGE_PATH" default:"./binaries"`
	DebugEnabled      bool   `env:"REDFLAG_DEBUG" default:"false"` // Enable debug logging
	SecurityLogging   struct {
		Enabled           bool   `env:"REDFLAG_SECURITY_LOG_ENABLED" default:"true"`
		Level             string `env:"REDFLAG_SECURITY_LOG_LEVEL" default:"warning"` // none, error, warn, info, debug
		LogSuccesses      bool   `env:"REDFLAG_SECURITY_LOG_SUCCESSES" default:"false"`
		FilePath          string `env:"REDFLAG_SECURITY_LOG_PATH" default:"/var/log/redflag/security.json"`
		MaxSizeMB         int    `env:"REDFLAG_SECURITY_LOG_MAX_SIZE" default:"100"`
		MaxFiles          int    `env:"REDFLAG_SECURITY_LOG_MAX_FILES" default:"10"`
		RetentionDays     int    `env:"REDFLAG_SECURITY_LOG_RETENTION" default:"90"`
		LogToDatabase     bool   `env:"REDFLAG_SECURITY_LOG_TO_DB" default:"true"`
		HashIPAddresses   bool   `env:"REDFLAG_SECURITY_LOG_HASH_IP" default:"true"`
	}
}

// IsDockerSecretsMode returns true if the application is running in Docker secrets mode
func IsDockerSecretsMode() bool {
	// Check if we're running in Docker and secrets are available
	if _, err := os.Stat("/run/secrets"); err == nil {
		// Also check if any RedFlag secrets exist
		if _, err := os.Stat("/run/secrets/redflag_admin_password"); err == nil {
			return true
		}
	}
	// Check environment variable override
	return os.Getenv("REDFLAG_SECRETS_MODE") == "true"
}

// getSecretPath returns the full path to a Docker secret file
func getSecretPath(secretName string) string {
	return filepath.Join("/run/secrets", secretName)
}

// loadFromSecrets reads configuration from Docker secrets
func loadFromSecrets(cfg *Config) error {
	// Note: For Docker secrets, we need to map environment variables differently
	// Docker secrets appear as files that contain the secret value
	fmt.Printf("[CONFIG] Loading configuration from Docker secrets\n")

	// Load sensitive values from Docker secrets
	if password, err := readSecretFile("redflag_admin_password"); err == nil && password != "" {
		cfg.Admin.Password = password
		fmt.Printf("[CONFIG] [OK] Admin password loaded from Docker secret\n")
	}

	if jwtSecret, err := readSecretFile("redflag_jwt_secret"); err == nil && jwtSecret != "" {
		cfg.Admin.JWTSecret = jwtSecret
		fmt.Printf("[CONFIG] [OK] JWT secret loaded from Docker secret\n")
	}

	if dbPassword, err := readSecretFile("redflag_db_password"); err == nil && dbPassword != "" {
		cfg.Database.Password = dbPassword
		fmt.Printf("[CONFIG] [OK] Database password loaded from Docker secret\n")
	}

	if signingKey, err := readSecretFile("redflag_signing_private_key"); err == nil && signingKey != "" {
		cfg.SigningPrivateKey = signingKey
		fmt.Printf("[CONFIG] [OK] Signing private key loaded from Docker secret (%d characters)\n", len(signingKey))
	}

	// For other configuration, fall back to environment variables
	// This allows mixing secrets (for sensitive data) with env vars (for non-sensitive config)
	return loadFromEnv(cfg, true)
}

// loadFromEnv reads configuration from environment variables
// If skipSensitive=true, it won't override values that might have come from secrets
func loadFromEnv(cfg *Config, skipSensitive bool) error {
	if !skipSensitive {
		fmt.Printf("[CONFIG] Loading configuration from environment variables\n")
	}

	// Parse server configuration
	if !skipSensitive || cfg.Server.Host == "" {
		cfg.Server.Host = getEnv("REDFLAG_SERVER_HOST", "0.0.0.0")
	}
	serverPort, _ := strconv.Atoi(getEnv("REDFLAG_SERVER_PORT", "8080"))
	cfg.Server.Port = serverPort
	cfg.Server.PublicURL = getEnv("REDFLAG_PUBLIC_URL", "") // Optional external URL
	cfg.Server.TLS.Enabled = getEnv("REDFLAG_TLS_ENABLED", "false") == "true"
	cfg.Server.TLS.CertFile = getEnv("REDFLAG_TLS_CERT_FILE", "")
	cfg.Server.TLS.KeyFile = getEnv("REDFLAG_TLS_KEY_FILE", "")

	// Parse database configuration
	cfg.Database.Host = getEnv("REDFLAG_DB_HOST", "localhost")
	dbPort, _ := strconv.Atoi(getEnv("REDFLAG_DB_PORT", "5432"))
	cfg.Database.Port = dbPort
	cfg.Database.Database = getEnv("REDFLAG_DB_NAME", "redflag")
	cfg.Database.Username = getEnv("REDFLAG_DB_USER", "redflag")

	// Only load password from env if we're not skipping sensitive data
	if !skipSensitive {
		cfg.Database.Password = getEnv("REDFLAG_DB_PASSWORD", "")
	}

	// Parse admin configuration
	cfg.Admin.Username = getEnv("REDFLAG_ADMIN_USER", "admin")
	if !skipSensitive {
		cfg.Admin.Password = getEnv("REDFLAG_ADMIN_PASSWORD", "")
		cfg.Admin.JWTSecret = getEnv("REDFLAG_JWT_SECRET", "")
	}

	// Parse agent registration configuration
	cfg.AgentRegistration.TokenExpiry = getEnv("REDFLAG_TOKEN_EXPIRY", "24h")
	maxTokens, _ := strconv.Atoi(getEnv("REDFLAG_MAX_TOKENS", "100"))
	cfg.AgentRegistration.MaxTokens = maxTokens
	maxSeats, _ := strconv.Atoi(getEnv("REDFLAG_MAX_SEATS", "50"))
	cfg.AgentRegistration.MaxSeats = maxSeats

	// Parse legacy configuration for backwards compatibility
	checkInInterval, _ := strconv.Atoi(getEnv("CHECK_IN_INTERVAL", "300"))
	offlineThreshold, _ := strconv.Atoi(getEnv("OFFLINE_THRESHOLD", "600"))
	cfg.CheckInInterval = checkInInterval
	cfg.OfflineThreshold = offlineThreshold
	cfg.Timezone = getEnv("TIMEZONE", "UTC")
	cfg.LatestAgentVersion = getEnv("LATEST_AGENT_VERSION", "0.1.26")
	cfg.MinAgentVersion = getEnv("MIN_AGENT_VERSION", "0.1.22")

	cfg.BinaryStoragePath = getEnv("REDFLAG_BINARY_STORAGE_PATH", "./binaries")

	if !skipSensitive {
		cfg.SigningPrivateKey = getEnv("REDFLAG_SIGNING_PRIVATE_KEY", "")
	}

	return nil
}

// readSecretFile reads a Docker secret from /run/secrets/ directory
func readSecretFile(secretName string) (string, error) {
	path := getSecretPath(secretName)
	data, err := os.ReadFile(path)
	if err != nil {
		return "", fmt.Errorf("failed to read secret %s from %s: %w", secretName, path, err)
	}
	return strings.TrimSpace(string(data)), nil
}

// Load reads configuration from Docker secrets or environment variables
func Load() (*Config, error) {
	// Check if we're in Docker secrets mode
	if IsDockerSecretsMode() {
		fmt.Printf("[CONFIG] Detected Docker secrets mode\n")
		cfg := &Config{}
		if err := loadFromSecrets(cfg); err != nil {
			return nil, fmt.Errorf("failed to load configuration from secrets: %w", err)
		}
		return cfg, nil
	}

	// Default to environment variable mode
	cfg := &Config{}
	if err := loadFromEnv(cfg, false); err != nil {
		return nil, fmt.Errorf("failed to load configuration from environment: %w", err)
	}

	// Continue with the rest of the validation...
	return cfg, nil
}


// RunSetupWizard is deprecated - configuration is now handled via web interface
func RunSetupWizard() error {
	return fmt.Errorf("CLI setup wizard is deprecated. Please use the web interface at http://localhost:8080/setup for configuration")
}

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

// GenerateSecurePassword generates a secure password (16 characters)
func GenerateSecurePassword() string {
	bytes := make([]byte, 16)
	rand.Read(bytes)
	// Use alphanumeric characters for better UX
	chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	result := make([]byte, 16)
	for i := range result {
		result[i] = chars[int(bytes[i])%len(chars)]
	}
	return string(result)
}

// GenerateSecureToken generates a cryptographically secure random token
func GenerateSecureToken() (string, error) {
	bytes := make([]byte, 32)
	if _, err := rand.Read(bytes); err != nil {
		return "", fmt.Errorf("failed to generate secure token: %w", err)
	}
	return hex.EncodeToString(bytes), nil
}
