package config

import (
	"fmt"
	"strings"

	"github.com/spf13/viper"
)

// Config holds all application configuration.
// Values are loaded from config.yaml then overridden by env vars prefixed with VEYLANT_.
// Example: VEYLANT_SERVER_PORT=9090 overrides server.port.
type Config struct {
	Server     ServerConfig     `mapstructure:"server"`
	Database   DatabaseConfig   `mapstructure:"database"`
	Redis      RedisConfig      `mapstructure:"redis"`
	Auth       AuthConfig       `mapstructure:"auth"`
	PII        PIIConfig        `mapstructure:"pii"`
	Log        LogConfig        `mapstructure:"log"`
	Providers  ProvidersConfig  `mapstructure:"providers"`
	RBAC       RBACConfig       `mapstructure:"rbac"`
	Metrics    MetricsConfig    `mapstructure:"metrics"`
	Routing    RoutingConfig    `mapstructure:"routing"`
	ClickHouse ClickHouseConfig `mapstructure:"clickhouse"`
	Crypto     CryptoConfig     `mapstructure:"crypto"`
	RateLimit  RateLimitConfig  `mapstructure:"rate_limit"`
}

// RateLimitConfig holds default rate limiting parameters applied to all tenants
// that have no explicit per-tenant override in the rate_limit_configs table.
type RateLimitConfig struct {
	// DefaultTenantRPM is the default tenant-wide requests per minute limit.
	DefaultTenantRPM int `mapstructure:"default_tenant_rpm"`
	// DefaultTenantBurst is the maximum burst size for a tenant bucket.
	DefaultTenantBurst int `mapstructure:"default_tenant_burst"`
	// DefaultUserRPM is the default per-user requests per minute limit within a tenant.
	DefaultUserRPM int `mapstructure:"default_user_rpm"`
	// DefaultUserBurst is the maximum burst size for a per-user bucket.
	DefaultUserBurst int `mapstructure:"default_user_burst"`
}

// ClickHouseConfig holds ClickHouse connection settings for the audit log.
type ClickHouseConfig struct {
	DSN            string `mapstructure:"dsn"`             // clickhouse://user:pass@host:9000/db
	MaxConns       int    `mapstructure:"max_conns"`
	DialTimeoutSec int    `mapstructure:"dial_timeout_seconds"`
}

// CryptoConfig holds cryptographic settings.
type CryptoConfig struct {
	// AESKeyBase64 is a base64-encoded 32-byte key for AES-256-GCM prompt encryption.
	// Set via env var VEYLANT_CRYPTO_AES_KEY_BASE64 — never hardcode.
	AESKeyBase64 string `mapstructure:"aes_key_base64"`
}

// RoutingConfig controls the intelligent routing engine behaviour.
type RoutingConfig struct {
	// CacheTTLSeconds is how long routing rules are cached per tenant before
	// a background refresh. 0 means use the default (30s).
	CacheTTLSeconds int `mapstructure:"cache_ttl_seconds"`
}

// ProvidersConfig holds configuration for all LLM provider adapters.
type ProvidersConfig struct {
	OpenAI    OpenAIConfig    `mapstructure:"openai"`
	Anthropic AnthropicConfig `mapstructure:"anthropic"`
	Azure     AzureConfig     `mapstructure:"azure"`
	Mistral   MistralConfig   `mapstructure:"mistral"`
	Ollama    OllamaConfig    `mapstructure:"ollama"`
}

// OpenAIConfig holds OpenAI adapter configuration.
type OpenAIConfig struct {
	APIKey         string `mapstructure:"api_key"`
	BaseURL        string `mapstructure:"base_url"`
	TimeoutSeconds int    `mapstructure:"timeout_seconds"`
	MaxConns       int    `mapstructure:"max_conns"`
}

// AnthropicConfig holds Anthropic adapter configuration.
type AnthropicConfig struct {
	APIKey         string `mapstructure:"api_key"`
	BaseURL        string `mapstructure:"base_url"`
	Version        string `mapstructure:"version"` // Anthropic API version header, e.g. "2023-06-01"
	TimeoutSeconds int    `mapstructure:"timeout_seconds"`
	MaxConns       int    `mapstructure:"max_conns"`
}

// AzureConfig holds Azure OpenAI adapter configuration.
type AzureConfig struct {
	APIKey         string `mapstructure:"api_key"`
	ResourceName   string `mapstructure:"resource_name"` // e.g. "my-azure-resource"
	DeploymentID   string `mapstructure:"deployment_id"` // e.g. "gpt-4o"
	APIVersion     string `mapstructure:"api_version"`   // e.g. "2024-02-01"
	TimeoutSeconds int    `mapstructure:"timeout_seconds"`
	MaxConns       int    `mapstructure:"max_conns"`
}

// MistralConfig holds Mistral AI adapter configuration (OpenAI-compatible).
type MistralConfig struct {
	APIKey         string `mapstructure:"api_key"`
	BaseURL        string `mapstructure:"base_url"`
	TimeoutSeconds int    `mapstructure:"timeout_seconds"`
	MaxConns       int    `mapstructure:"max_conns"`
}

// OllamaConfig holds Ollama adapter configuration (OpenAI-compatible, local).
type OllamaConfig struct {
	BaseURL        string `mapstructure:"base_url"`
	TimeoutSeconds int    `mapstructure:"timeout_seconds"`
	MaxConns       int    `mapstructure:"max_conns"`
}

// RBACConfig holds role-based access control settings for the provider router.
type RBACConfig struct {
	// UserAllowedModels lists models accessible to the "user" role (exact or prefix match).
	UserAllowedModels []string `mapstructure:"user_allowed_models"`
	// AuditorCanComplete controls whether auditors can make chat completions.
	// Defaults to false — auditors receive 403 on POST /v1/chat/completions.
	AuditorCanComplete bool `mapstructure:"auditor_can_complete"`
}

// MetricsConfig holds Prometheus metrics configuration.
type MetricsConfig struct {
	Enabled bool   `mapstructure:"enabled"`
	Path    string `mapstructure:"path"`
}

type ServerConfig struct {
	Port            int      `mapstructure:"port"`
	ShutdownTimeout int      `mapstructure:"shutdown_timeout_seconds"`
	Env             string   `mapstructure:"env"`             // development, staging, production
	TenantName      string   `mapstructure:"tenant_name"`     // display name used in PDF reports
	AllowedOrigins  []string `mapstructure:"allowed_origins"` // CORS allowed origins for the React dashboard
}

type DatabaseConfig struct {
	URL             string `mapstructure:"url"`
	MaxOpenConns    int    `mapstructure:"max_open_conns"`
	MaxIdleConns    int    `mapstructure:"max_idle_conns"`
	MigrationsPath  string `mapstructure:"migrations_path"`
}

type RedisConfig struct {
	URL string `mapstructure:"url"`
}

// AuthConfig holds local JWT authentication settings.
// Override via VEYLANT_AUTH_JWT_SECRET and VEYLANT_AUTH_JWT_TTL_HOURS.
type AuthConfig struct {
	JWTSecret   string `mapstructure:"jwt_secret"`
	JWTTTLHours int    `mapstructure:"jwt_ttl_hours"`
}

type PIIConfig struct {
	Enabled     bool   `mapstructure:"enabled"`
	ServiceAddr string `mapstructure:"service_addr"` // gRPC address, e.g. localhost:50051
	TimeoutMs   int    `mapstructure:"timeout_ms"`
	FailOpen    bool   `mapstructure:"fail_open"` // if true, pass request through on PII service error
}

type LogConfig struct {
	Level  string `mapstructure:"level"`  // debug, info, warn, error
	Format string `mapstructure:"format"` // json, console
}

// Load reads configuration from config.yaml (searched in . and ./config)
// and overrides with environment variables prefixed VEYLANT_.
func Load() (*Config, error) {
	v := viper.New()

	v.SetConfigName("config")
	v.SetConfigType("yaml")
	v.AddConfigPath(".")
	v.AddConfigPath("./config")

	// Env var overrides: VEYLANT_SERVER_PORT → server.port
	v.SetEnvPrefix("VEYLANT")
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	v.AutomaticEnv()

	// Defaults
	v.SetDefault("server.port", 8090)
	v.SetDefault("server.shutdown_timeout_seconds", 30)
	v.SetDefault("server.env", "development")
	v.SetDefault("server.allowed_origins", []string{"http://localhost:3000"})
	v.SetDefault("database.max_open_conns", 25)
	v.SetDefault("database.max_idle_conns", 5)
	v.SetDefault("database.migrations_path", "migrations")
	v.SetDefault("auth.jwt_secret", "change-me-in-production-use-VEYLANT_AUTH_JWT_SECRET")
	v.SetDefault("auth.jwt_ttl_hours", 24)
	v.SetDefault("pii.enabled", false)
	v.SetDefault("pii.service_addr", "localhost:50051")
	v.SetDefault("pii.timeout_ms", 100)
	v.SetDefault("pii.fail_open", true)
	v.SetDefault("log.level", "info")
	v.SetDefault("log.format", "json")
	v.SetDefault("providers.openai.base_url", "https://api.openai.com/v1")
	v.SetDefault("providers.openai.timeout_seconds", 30)
	v.SetDefault("providers.openai.max_conns", 100)
	v.SetDefault("providers.anthropic.base_url", "https://api.anthropic.com/v1")
	v.SetDefault("providers.anthropic.version", "2023-06-01")
	v.SetDefault("providers.anthropic.timeout_seconds", 30)
	v.SetDefault("providers.anthropic.max_conns", 100)
	v.SetDefault("providers.azure.api_version", "2024-02-01")
	v.SetDefault("providers.azure.timeout_seconds", 30)
	v.SetDefault("providers.azure.max_conns", 100)
	v.SetDefault("providers.mistral.base_url", "https://api.mistral.ai/v1")
	v.SetDefault("providers.mistral.timeout_seconds", 30)
	v.SetDefault("providers.mistral.max_conns", 100)
	v.SetDefault("providers.ollama.base_url", "http://localhost:11434/v1")
	v.SetDefault("providers.ollama.timeout_seconds", 120)
	v.SetDefault("providers.ollama.max_conns", 10)
	v.SetDefault("rbac.user_allowed_models", []string{"gpt-4o-mini", "gpt-3.5-turbo", "mistral-small"})
	v.SetDefault("rbac.auditor_can_complete", false)
	v.SetDefault("metrics.enabled", true)
	v.SetDefault("metrics.path", "/metrics")
	v.SetDefault("routing.cache_ttl_seconds", 30)
	v.SetDefault("clickhouse.max_conns", 10)
	v.SetDefault("clickhouse.dial_timeout_seconds", 5)
	v.SetDefault("rate_limit.default_tenant_rpm", 1000)
	v.SetDefault("rate_limit.default_tenant_burst", 200)
	v.SetDefault("rate_limit.default_user_rpm", 100)
	v.SetDefault("rate_limit.default_user_burst", 20)

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

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

	return &cfg, nil
}
