//go:build e2e

package e2e

import (
	"os"
	"path/filepath"

	"gopkg.in/yaml.v2"
)

// E2EConfig holds the configuration for E2E tests
type E2EConfig struct {
	// Mode can be "local" or "production"
	Mode string `yaml:"mode"`

	// BaseDomain is the domain used for deployment routing (e.g., "dbrs.space" or "orama.network")
	BaseDomain string `yaml:"base_domain"`

	// Servers is a list of production servers (only used when mode=production)
	Servers []ServerConfig `yaml:"servers"`

	// Nameservers is a list of nameserver hostnames (e.g., ["ns1.dbrs.space", "ns2.dbrs.space"])
	Nameservers []string `yaml:"nameservers"`

	// APIKey is the API key for production testing (auto-discovered if empty)
	APIKey string `yaml:"api_key"`
}

// ServerConfig holds configuration for a single production server
type ServerConfig struct {
	Name         string `yaml:"name"`
	IP           string `yaml:"ip"`
	User         string `yaml:"user"`
	Password     string `yaml:"password"`
	IsNameserver bool   `yaml:"is_nameserver"`
}

// DefaultConfig returns the default configuration
func DefaultConfig() *E2EConfig {
	return &E2EConfig{
		Mode:        "production",
		BaseDomain:  "orama.network",
		Servers:     []ServerConfig{},
		Nameservers: []string{},
		APIKey:      "",
	}
}

// LoadE2EConfig loads the E2E test configuration from e2e/config.yaml
// Falls back to defaults if the file doesn't exist
func LoadE2EConfig() (*E2EConfig, error) {
	// Try multiple locations for the config file
	configPaths := []string{
		"config.yaml",       // Relative to e2e directory (when running from e2e/)
		"e2e/config.yaml",   // Relative to project root
		"../e2e/config.yaml", // From subdirectory within e2e/
	}

	// Also try absolute path based on working directory
	if cwd, err := os.Getwd(); err == nil {
		configPaths = append(configPaths, filepath.Join(cwd, "config.yaml"))
		configPaths = append(configPaths, filepath.Join(cwd, "e2e", "config.yaml"))
		// Go up one level if we're in a subdirectory
		configPaths = append(configPaths, filepath.Join(cwd, "..", "config.yaml"))
	}

	var configData []byte
	var readErr error

	for _, path := range configPaths {
		data, err := os.ReadFile(path)
		if err == nil {
			configData = data
			break
		}
		readErr = err
	}

	// If no config file found, return defaults
	if configData == nil {
		// Check if running in production mode via environment variable
		if os.Getenv("E2E_MODE") == "production" {
			return nil, readErr // Config file required for production mode
		}
		return DefaultConfig(), nil
	}

	var cfg E2EConfig
	if err := yaml.Unmarshal(configData, &cfg); err != nil {
		return nil, err
	}

	// Apply defaults for empty values
	if cfg.Mode == "" {
		cfg.Mode = "production"
	}
	if cfg.BaseDomain == "" {
		cfg.BaseDomain = "orama.network"
	}

	return &cfg, nil
}

// IsProductionMode returns true if running in production mode
func IsProductionMode() bool {
	// Check environment variable first
	if os.Getenv("E2E_MODE") == "production" {
		return true
	}

	cfg, err := LoadE2EConfig()
	if err != nil {
		return false
	}
	return cfg.Mode == "production"
}

// GetServerIPs returns a list of all server IP addresses from config
func GetServerIPs(cfg *E2EConfig) []string {
	if cfg == nil {
		return nil
	}

	ips := make([]string, 0, len(cfg.Servers))
	for _, server := range cfg.Servers {
		if server.IP != "" {
			ips = append(ips, server.IP)
		}
	}
	return ips
}

// GetNameserverServers returns servers configured as nameservers
func GetNameserverServers(cfg *E2EConfig) []ServerConfig {
	if cfg == nil {
		return nil
	}

	var nameservers []ServerConfig
	for _, server := range cfg.Servers {
		if server.IsNameserver {
			nameservers = append(nameservers, server)
		}
	}
	return nameservers
}
