package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"gopkg.in/yaml.v3"
)

type Config struct {
	Env                   string   `yaml:"env"`
	Port                  string   `yaml:"port"`
	DSN                   string   `yaml:"dsn"`
	StorageDir            string   `yaml:"storage_dir"`
	MaxUploadBytes        int64    `yaml:"max_upload_bytes"`
	AuthSecret            string   `yaml:"auth_secret"`
	SystemAIKey           string   `yaml:"system_ai_key"`
	AIKeyEncryptionSecret string   `yaml:"ai_key_encryption_secret"`
	AllowedOrigins        []string `yaml:"allowed_origins"`
}

func Load() Config {
	cfg, err := LoadFromDir("etc")
	if err != nil {
		panic(err)
	}
	return cfg
}

func LoadFromDir(configDir string) (Config, error) {
	mode := strings.TrimSpace(os.Getenv("SENLIN_APP_MODE"))
	if mode == "" {
		mode = "dev"
	}
	path := filepath.Join(configDir, "agent."+strings.ToLower(mode)+".yaml")
	data, err := os.ReadFile(path)
	if err != nil {
		return Config{}, err
	}
	var cfg Config
	if err := yaml.Unmarshal(data, &cfg); err != nil {
		return Config{}, err
	}
	if cfg.MaxUploadBytes <= 0 {
		cfg.MaxUploadBytes = 32 << 20
	}
	if strings.TrimSpace(cfg.StorageDir) == "" {
		return Config{}, fmt.Errorf("storage_dir must not be empty")
	}
	hasAllowedOrigin := false
	for _, origin := range cfg.AllowedOrigins {
		if strings.TrimSpace(origin) != "" {
			hasAllowedOrigin = true
			break
		}
	}
	if !hasAllowedOrigin {
		return Config{}, fmt.Errorf("allowed_origins must include at least one origin")
	}
	if err := validateSecret(cfg.Env, "auth_secret", cfg.AuthSecret); err != nil {
		return Config{}, err
	}
	if err := validateSecret(cfg.Env, "ai_key_encryption_secret", cfg.AIKeyEncryptionSecret); err != nil {
		return Config{}, err
	}
	return cfg, nil
}

func validateSecret(environment, field, value string) error {
	secret := strings.TrimSpace(value)
	if secret == "" {
		return fmt.Errorf("%s must not be empty", field)
	}
	if strings.EqualFold(strings.TrimSpace(environment), "production") || strings.EqualFold(strings.TrimSpace(environment), "prod") {
		if len(secret) < 32 || isCommonSecret(secret) {
			return fmt.Errorf("%s must be at least 32 characters and must not use a development sentinel in production", field)
		}
	}
	return nil
}

func isCommonSecret(value string) bool {
	normalized := strings.ToLower(strings.TrimSpace(value))
	for _, marker := range []string{"change-me", "changeme", "development", "dev-secret", "local-secret", "test-secret", "placeholder"} {
		if strings.Contains(normalized, marker) {
			return true
		}
	}
	switch normalized {
	case "secret", "password", "default", "admin":
		return true
	default:
		return false
	}
}
