package config

import (
	"os"
	"strconv"

	"github.com/joho/godotenv"
	"github.com/pelletier/go-toml/v2"
)

// Config holds application configuration loaded from TOML
type Config struct {
	Server   ServerConfig   `toml:"server"`
	MQTT     MQTTConfig     `toml:"mqtt"`
	Database DatabaseConfig `toml:"database"`
}

type ServerConfig struct {
	Address   string `toml:"address"`
	Port      int    `toml:"port"`
	JWTSecret string `toml:"jwt_secret"`
}

type MQTTConfig struct {
	Broker   string `toml:"broker"`
	ClientID string `toml:"client_id"`
	Username string `toml:"username"`
	Password string `toml:"password"`
	Topic    string `toml:"topic"`
}

type DatabaseConfig struct {
	Host     string `toml:"host"`
	Port     int    `toml:"port"`
	User     string `toml:"user"`
	Password string `toml:"password"`
	Name     string `toml:"name"`
}

// Load loads configuration from the given path. If path is empty, it tries
// to load ./config.toml or falls back to environment defaults.
func Load(path string) (*Config, error) {
	cfg := &Config{
		Server: ServerConfig{
			Address:   "0.0.0.0",
			Port:      8080,
			JWTSecret: "secret",
		},
		MQTT: MQTTConfig{
			Broker:   "tcp://localhost:1883",
			ClientID: "lambda-iot-core",
			Topic:    "lambda/iot",
		},
		Database: DatabaseConfig{
			Host: "localhost",
			Port: 3306,
			User: "root",
			Name: "lambdaiot",
		},
	}

	// try to load TOML if provided or present
	if path == "" {
		path = "config.toml"
	}
	if _, err := os.Stat(path); err == nil {
		f, err := os.ReadFile(path)
		if err != nil {
			return nil, err
		}
		if err := toml.Unmarshal(f, cfg); err != nil {
			return nil, err
		}
	}

	// load .env (if present) so env vars are populated for overrides
	_ = godotenv.Load()

	// environment overrides (common for Docker/.env)
	if v := os.Getenv("SERVER_ADDRESS"); v != "" {
		cfg.Server.Address = v
	}
	if v := os.Getenv("SERVER_PORT"); v != "" {
		if p, err := strconv.Atoi(v); err == nil {
			cfg.Server.Port = p
		}
	}
	if v := os.Getenv("JWT_SECRET"); v != "" {
		cfg.Server.JWTSecret = v
	}

	if v := os.Getenv("MQTT_BROKER"); v != "" {
		cfg.MQTT.Broker = v
	}
	if v := os.Getenv("MQTT_CLIENT_ID"); v != "" {
		cfg.MQTT.ClientID = v
	}
	if v := os.Getenv("MQTT_USERNAME"); v != "" {
		cfg.MQTT.Username = v
	}
	if v := os.Getenv("MQTT_PASSWORD"); v != "" {
		cfg.MQTT.Password = v
	}
	if v := os.Getenv("MQTT_TOPIC"); v != "" {
		cfg.MQTT.Topic = v
	}

	if v := os.Getenv("DB_HOST"); v != "" {
		cfg.Database.Host = v
	}
	if v := os.Getenv("DB_PORT"); v != "" {
		if p, err := strconv.Atoi(v); err == nil {
			cfg.Database.Port = p
		}
	}
	if v := os.Getenv("DB_USER"); v != "" {
		cfg.Database.User = v
	}
	if v := os.Getenv("DB_PASSWORD"); v != "" {
		cfg.Database.Password = v
	}
	if v := os.Getenv("DB_NAME"); v != "" {
		cfg.Database.Name = v
	}

	return cfg, nil
}
