package config

import (
	"fmt"
	"os"
	"strconv"

	"github.com/joho/godotenv"
)

// Config holds all application configuration.
type Config struct {
	Port        string
	DatabaseURL string
	DBDriver    string // "postgres" (default) or "sqlite"
	JWTSecret   string
	Environment string
	BasePath    string // URL path prefix (e.g. "/dev", "/test", or "" for root)

	// Admin bootstrap (optional — set via K8s secret)
	AdminUsername string
	AdminPassword string
	AdminEmail    string

	// Seed users (dev/test only) — CSV: "user:pass:role,user2:pass2:role2"
	SeedUsers string

	// API key encryption (required for v0.9.4+)
	// Used to derive AES-256 key for global/team provider API keys.
	// Personal keys use per-user UEK (derived from password).
	EncryptionKey string

	// File storage (v0.12.0+)
	// STORAGE_BACKEND: "pvc" or "s3". Empty = auto-detect (pvc if path writable).
	// STORAGE_PATH: mount point for PVC backend (default /data/storage).
	StorageBackend string
	StoragePath    string

	// S3-compatible storage (v0.12.0+)
	// Works with AWS S3, MinIO, Ceph RGW, or any S3-compatible API.
	S3Endpoint       string // custom endpoint URL (required for MinIO/Ceph, optional for AWS)
	S3Bucket         string // bucket name (required when STORAGE_BACKEND=s3)
	S3Region         string // AWS region (default "us-east-1")
	S3AccessKey      string // access key ID
	S3SecretKey      string // secret access key
	S3Prefix         string // optional key prefix within bucket (e.g. "switchboard/")
	S3ForcePathStyle bool   // use path-style URLs (required for MinIO, most self-hosted)

	// Structured logging (v0.33.0)
	// LOG_FORMAT: "text" (default, backward-compatible) or "json" (structured).
	// LOG_LEVEL: "debug", "info" (default), "warn", "error".
	LogFormat string
	LogLevel  string

	// Auth mode (v0.24.0): "builtin" (default) | "mtls" | "oidc"
	AuthMode string

	// mTLS (v0.24.1)
	// Headers injected by TLS-terminating reverse proxy.
	MTLSHeaderDN          string // default "X-SSL-Client-DN"
	MTLSHeaderVerify      string // default "X-SSL-Client-Verify"
	MTLSHeaderFingerprint string // default "X-SSL-Client-Fingerprint"
	MTLSAutoActivate      bool   // auto-activate new users (default true)
	MTLSDefaultTeam       string // team ID for auto-provisioned users (optional)

	// Bundled packages (v0.3.8)
	// SKIP_BUNDLED_PACKAGES: set true to disable auto-install of bundled packages on first run.
	// BUNDLED_PACKAGES_DIR: directory containing pre-built .pkg archives (default /app/bundled-packages).
	// BUNDLED_PACKAGES: comma-separated allowlist of package IDs to install (empty = all).
	//   e.g. "tasks,schedules,hello-dashboard" installs only those three.
	SkipBundledPackages bool
	BundledPackagesDir  string
	BundledPackages     string

	// OIDC (v0.24.1)
	OIDCIssuerURL    string // e.g. "https://keycloak.corp/realms/switchboard"
	OIDCExternalIssuerURL string  // OIDC_EXTERNAL_ISSUER_URL
	OIDCClientID     string
	OIDCClientSecret string
	OIDCRedirectURL  string // e.g. "https://switchboard.corp/api/v1/auth/oidc/callback"
	OIDCAutoActivate bool   // auto-activate new users (default true)
	OIDCDefaultTeam  string // team ID for auto-provisioned users (optional)
	OIDCRolesClaim   string // JWT claim for role mapping (default "realm_access.roles")
	OIDCGroupsClaim  string // JWT claim for group sync (default "groups")
	OIDCAdminRole    string // IdP role value that maps to admin (default "admin")
}

// Load reads configuration from environment variables.
// A .env file is loaded if present but not required.
func Load() *Config {
	// Best-effort .env load (not required in production)
	_ = godotenv.Load()

	return &Config{
		Port:          getEnv("PORT", "8080"),
		DatabaseURL:   resolveDatabaseURL(),
		DBDriver:      getEnv("DB_DRIVER", ""),
		JWTSecret:     getEnv("JWT_SECRET", "dev-secret-change-me"),
		Environment:   getEnv("ENVIRONMENT", "development"),
		BasePath:      sanitizeBasePath(getEnv("BASE_PATH", "")),
		AdminUsername: getEnv("SWITCHBOARD_ADMIN_USERNAME", ""),
		AdminPassword: getEnv("SWITCHBOARD_ADMIN_PASSWORD", ""),
		AdminEmail:    getEnv("SWITCHBOARD_ADMIN_EMAIL", ""),
		SeedUsers:     getEnv("SEED_USERS", ""),
		EncryptionKey: getEnv("ENCRYPTION_KEY", ""),

		StorageBackend:        getEnv("STORAGE_BACKEND", ""),
		StoragePath:           getEnv("STORAGE_PATH", "/data/storage"),
		S3Endpoint:            getEnv("S3_ENDPOINT", ""),
		S3Bucket:              getEnv("S3_BUCKET", ""),
		S3Region:              getEnv("S3_REGION", "us-east-1"),
		S3AccessKey:           getEnv("S3_ACCESS_KEY", ""),
		S3SecretKey:           getEnv("S3_SECRET_KEY", ""),
		S3Prefix:              getEnv("S3_PREFIX", ""),
		S3ForcePathStyle:      getEnv("S3_FORCE_PATH_STYLE", "true") == "true",

		SkipBundledPackages: getEnvBool("SKIP_BUNDLED_PACKAGES", false),
		BundledPackagesDir:  getEnv("BUNDLED_PACKAGES_DIR", "/app/bundled-packages"),
		BundledPackages:     getEnv("BUNDLED_PACKAGES", ""),

		LogFormat: getEnv("LOG_FORMAT", "text"),
		LogLevel:  getEnv("LOG_LEVEL", "info"),

		AuthMode: getEnv("AUTH_MODE", "builtin"),

		// mTLS
		MTLSHeaderDN:          getEnv("MTLS_HEADER_DN", "X-SSL-Client-DN"),
		MTLSHeaderVerify:      getEnv("MTLS_HEADER_VERIFY", "X-SSL-Client-Verify"),
		MTLSHeaderFingerprint: getEnv("MTLS_HEADER_FINGERPRINT", "X-SSL-Client-Fingerprint"),
		MTLSAutoActivate:      getEnvBool("MTLS_AUTO_ACTIVATE", true),
		MTLSDefaultTeam:       getEnv("MTLS_DEFAULT_TEAM", ""),

		// OIDC
		OIDCIssuerURL:            getEnv("OIDC_ISSUER_URL", ""),
		OIDCExternalIssuerURL:    getEnv("OIDC_EXTERNAL_ISSUER_URL", ""),
		OIDCClientID:     getEnv("OIDC_CLIENT_ID", ""),
		OIDCClientSecret: getEnv("OIDC_CLIENT_SECRET", ""),
		OIDCRedirectURL:  getEnv("OIDC_REDIRECT_URL", ""),
		OIDCAutoActivate: getEnvBool("OIDC_AUTO_ACTIVATE", true),
		OIDCDefaultTeam:  getEnv("OIDC_DEFAULT_TEAM", ""),
		OIDCRolesClaim:   getEnv("OIDC_ROLES_CLAIM", "realm_access.roles"),
		OIDCGroupsClaim:  getEnv("OIDC_GROUPS_CLAIM", "groups"),
		OIDCAdminRole:    getEnv("OIDC_ADMIN_ROLE", "admin"),
	}
}

// resolveDatabaseURL returns the database connection string.
//
// Resolution order:
//  1. DATABASE_URL — explicit DSN (K8s, .env, manual)
//  2. POSTGRES_* vars — assembled from individual env vars:
//     POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB
//     (set by K8s manifest and docker-compose)
//  3. Empty string — backend runs without database
func resolveDatabaseURL() string {
	if dsn := os.Getenv("DATABASE_URL"); dsn != "" {
		return dsn
	}
	// Assemble from individual vars (K8s sets POSTGRES_*, docker-compose may too)
	host := getEnv("POSTGRES_HOST", "")
	if host == "" {
		return ""
	}
	port := getEnv("POSTGRES_PORT", "5432")
	user := getEnv("POSTGRES_USER", "")
	pass := getEnv("POSTGRES_PASSWORD", "")
	db := getEnv("POSTGRES_DB", "switchboard_core")
	ssl := getEnv("POSTGRES_SSLMODE", "disable")
	return fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", user, pass, host, port, db, ssl)
}

// sanitizeBasePath ensures the path starts with / and doesn't end with /.
// Empty string means root (no prefix).
func sanitizeBasePath(p string) string {
	if p == "" || p == "/" {
		return ""
	}
	// Ensure leading slash
	if p[0] != '/' {
		p = "/" + p
	}
	// Strip trailing slash
	for len(p) > 1 && p[len(p)-1] == '/' {
		p = p[:len(p)-1]
	}
	return p
}

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

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

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