package config

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

// Config holds all application configuration
type Config struct {
	Database DatabaseConfig
	AI       AIConfig
	UI       UIConfig
}

type DatabaseConfig struct {
	Path            string
	MaxOpenConns    int
	MaxIdleConns    int
	ConnMaxLifetime int // in minutes
}

type AIConfig struct {
	DefaultModel      string
	Models            []AIModelConfig
	MaxRetries        int
	RetryDelay        int      // in milliseconds
	OllamaBaseURL     string   // URL for Ollama API
	Timeout           int      // request timeout in seconds
	RequestsPerMinute int      // Rate limit in requests per minute
	BurstLimit        int      // Maximum burst size for rate limiter
	BackgroundEnabled bool     // Whether to enable background analysis
	MaxTokens         int      // Maximum tokens to generate in responses
	RetryableErrors   []string // List of error strings that should trigger retries
}

type AIModelConfig struct {
	Name      string
	Provider  string
	APIKey    string
	Priority  int      // Lower numbers mean higher priority
	Tags      []string // Model capabilities/specialties
	MaxTokens int      // Maximum tokens per request
}

type UIConfig struct {
	Theme           string
	RefreshInterval int // in seconds
	IdleStartHour   int // Hour to start background analysis (24h format)
	IdleEndHour     int // Hour to end background analysis (24h format)
	MaxDisplayTasks int
}

// LoadConfig loads configuration from environment variables
func LoadConfig() (*Config, error) {
	cfg := &Config{
		Database: DatabaseConfig{
			Path:            getEnv("DB_PATH", "todoai.db"),
			MaxOpenConns:    getEnvInt("DB_MAX_OPEN_CONNS", 25),
			MaxIdleConns:    getEnvInt("DB_MAX_IDLE_CONNS", 5),
			ConnMaxLifetime: getEnvInt("DB_CONN_MAX_LIFETIME", 5),
		},
		AI: AIConfig{
			DefaultModel:      getEnv("AI_DEFAULT_MODEL", "gemma3:1b"),
			MaxRetries:        getEnvInt("AI_MAX_RETRIES", 3),
			RetryDelay:        getEnvInt("AI_RETRY_DELAY_MS", 500),
			OllamaBaseURL:     getEnv("AI_OLLAMA_URL", "http://localhost:11434"),
			Timeout:           getEnvInt("AI_TIMEOUT_SECONDS", 10),
			RequestsPerMinute: getEnvInt("AI_REQUESTS_PER_MINUTE", 10),
			BurstLimit:        getEnvInt("AI_BURST_LIMIT", 3),
			BackgroundEnabled: getEnvBool("AI_BACKGROUND_ENABLED", true),
			MaxTokens:         getEnvInt("AI_MAX_TOKENS", 2048),
			RetryableErrors: getEnvArray("AI_RETRYABLE_ERRORS", []string{
				"connection refused",
				"timeout",
				"too many requests",
				"server error",
			}),
			Models: []AIModelConfig{
				{
					Name:      getEnv("AI_MODEL_NAME", "gemma3:1b"),
					Provider:  getEnv("AI_PROVIDER", "ollama"),
					APIKey:    getEnv("AI_API_KEY", ""),
					Priority:  1,
					Tags:      getEnvArray("AI_MODEL_TAGS", []string{"general"}),
					MaxTokens: getEnvInt("AI_MAX_TOKENS", 2048),
				},
				{
					Name:      "mistral:7b",
					Provider:  "ollama",
					Priority:  2,
					Tags:      []string{"general", "fallback"},
					MaxTokens: 2048,
				},
			},
		},
		UI: UIConfig{
			Theme:           getEnv("UI_THEME", "default"),
			RefreshInterval: getEnvInt("UI_REFRESH_INTERVAL", 60),
			IdleStartHour:   getEnvInt("UI_IDLE_START_HOUR", 22),
			IdleEndHour:     getEnvInt("UI_IDLE_END_HOUR", 6),
			MaxDisplayTasks: getEnvInt("UI_MAX_DISPLAY_TASKS", 100),
		},
	}

	return cfg, cfg.validate()
}

func (c *Config) validate() error {
	if c.Database.Path == "" {
		return fmt.Errorf("database path cannot be empty")
	}

	if len(c.AI.Models) == 0 {
		return fmt.Errorf("at least one AI model must be configured")
	}

	if c.AI.RequestsPerMinute < 1 {
		return fmt.Errorf("AI requests per minute must be at least 1")
	}

	if c.AI.BurstLimit < 1 {
		return fmt.Errorf("AI burst limit must be at least 1")
	}

	if c.UI.IdleStartHour < 0 || c.UI.IdleStartHour > 23 {
		return fmt.Errorf("idle start hour must be between 0 and 23")
	}

	if c.UI.IdleEndHour < 0 || c.UI.IdleEndHour > 23 {
		return fmt.Errorf("idle end hour must be between 0 and 23")
	}

	return nil
}

func getEnv(key, defaultValue string) string {
	if value, exists := os.LookupEnv(key); exists {
		return value
	}
	return defaultValue
}

func getEnvInt(key string, defaultValue int) int {
	if value, exists := os.LookupEnv(key); exists {
		if intVal, err := strconv.Atoi(value); err == nil {
			return intVal
		}
	}
	return defaultValue
}

func getEnvArray(key string, defaultValue []string) []string {
	if value, exists := os.LookupEnv(key); exists {
		return strings.Split(value, ",")
	}
	return defaultValue
}

func getEnvBool(key string, fallback bool) bool {
	if value, ok := os.LookupEnv(key); ok {
		if b, err := strconv.ParseBool(value); err == nil {
			return b
		}
	}
	return fallback
}
