package config

import (
	"encoding/json"
	"github.com/joho/godotenv"
	"log/slog"
	"os"
	"regexp"
	"yobble-gateway-go/internal/logger"

	"gopkg.in/yaml.v3"
)

// Backend представляет собой отдельный сервер бэкенда.
type Backend struct {
	URL             string `json:"url"`
	Role            string `json:"role"`
	AllowSelfSigned bool   `json:"allow_self_signed"`
}

// Routes сопоставляет строки версий с префиксами маршрутов и бэкендами.
type Routes map[string]map[string][]Backend

// ServerConfig содержит настройки, связанные с сервером.
type ServerConfig struct {
	Host string `yaml:"host"`
	Port string `yaml:"port"`
}

// GatewayConfig содержит настройки, специфичные для шлюза.
type GatewayConfig struct {
	RouteFile        string   `yaml:"route_file"`
	GeoIPDB          string   `yaml:"geoip_db"`
	BlockedCountries []string `yaml:"blocked_countries"`
}

// TLSConfig содержит настройки, связанные с TLS.
type TLSConfig struct {
	FullChain  string `yaml:"full_chain"`
	PrivateKey string `yaml:"private_key"`
}

// LogConfig содержит настройки, связанные с логированием.
type LogConfig struct {
	Level  string `yaml:"level"`
	Format string `yaml:"format"`
}

// Settings содержит всю конфигурацию приложения.
type Settings struct {
	Server  ServerConfig  `yaml:"server"`
	Gateway GatewayConfig `yaml:"gateway"`
	TLS     TLSConfig     `yaml:"tls"`
	Logging LogConfig     `yaml:"logging"`

	RouteConfig Routes `yaml:"-"` // Загружается отдельно, не из корня YAML
}

// Load возвращает новый объект конфигурации, считывая YAML-файл.
func Load(configPath string) (*Settings, error) {
	op := "config.Load"
	log := logger.NewLoggerWithOp(op)

	if err := godotenv.Load(); err != nil {
		log.Warn("[Attention]: No .env file found or failed to load, using STANDARD settings!")
	}

	configFile, err := os.ReadFile(configPath)
	if err != nil {
		log.Error("failed to read config file", slog.String("path", configPath), slog.Any("error", err))
		return nil, err
	}
	processed := replaceEnvVars(string(configFile))

	var settings Settings
	if err := yaml.Unmarshal([]byte(processed), &settings); err != nil {
		log.Error("failed to unmarshal config file", slog.String("path", configPath), slog.Any("error", err))
		return nil, err
	}

	// Загружаем маршруты из JSON-файла
	routeFile, err := os.ReadFile(settings.Gateway.RouteFile)
	if err != nil {
		log.Error("failed to read route file", slog.String("path", settings.Gateway.RouteFile), slog.Any("error", err))
		return nil, err
	}

	var routes Routes
	if err := json.Unmarshal(routeFile, &routes); err != nil {
		log.Error("failed to unmarshal route file", slog.String("path", settings.Gateway.RouteFile), slog.Any("error", err))
		return nil, err
	}
	settings.RouteConfig = routes

	return &settings, nil
}

// replaceEnvVars Поддержка ${ENV_VAR:default} AKA SpringBoot
func replaceEnvVars(input string) string {
	re := regexp.MustCompile(`\$\{([^}:\s]+)(?::([^}]*))?\}`)
	return re.ReplaceAllStringFunc(input, func(s string) string {
		matches := re.FindStringSubmatch(s)
		envVar := matches[1]
		defVal := matches[2]
		val := os.Getenv(envVar)
		if val == "" {
			val = defVal
		}
		return val
	})
}
