package config

import (
	"fmt"
	"os"

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

// CLIConfig is the configuration for the mcp CLI binary.
type CLIConfig struct {
	Services ServicesConfig `toml:"services"`
	MCIAS    MCIASConfig    `toml:"mcias"`
	Auth     AuthConfig     `toml:"auth"`
	Nodes    []NodeConfig   `toml:"nodes"`
}

// ServicesConfig defines where service definition files live.
type ServicesConfig struct {
	Dir string `toml:"dir"`
}

// MCIASConfig holds MCIAS connection settings, shared by CLI and agent.
type MCIASConfig struct {
	ServerURL   string `toml:"server_url"`
	CACert      string `toml:"ca_cert"`
	ServiceName string `toml:"service_name"`
}

// AuthConfig holds authentication settings for the CLI.
type AuthConfig struct {
	TokenPath    string `toml:"token_path"`
	Username     string `toml:"username"`      // optional, for unattended operation
	PasswordFile string `toml:"password_file"` // optional, for unattended operation
}

// NodeConfig defines a managed node that the CLI connects to.
type NodeConfig struct {
	Name    string `toml:"name"`
	Address string `toml:"address"`
}

// LoadCLIConfig reads and validates a CLI configuration file.
// Environment variables override file values for select fields.
func LoadCLIConfig(path string) (*CLIConfig, error) {
	data, err := os.ReadFile(path) //nolint:gosec // config path from trusted CLI flag
	if err != nil {
		return nil, fmt.Errorf("read config %q: %w", path, err)
	}

	var cfg CLIConfig
	if err := toml.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parse config %q: %w", path, err)
	}

	applyCLIEnvOverrides(&cfg)

	if err := validateCLIConfig(&cfg); err != nil {
		return nil, fmt.Errorf("validate config: %w", err)
	}

	return &cfg, nil
}

func applyCLIEnvOverrides(cfg *CLIConfig) {
	if v := os.Getenv("MCP_SERVICES_DIR"); v != "" {
		cfg.Services.Dir = v
	}
	if v := os.Getenv("MCP_MCIAS_SERVER_URL"); v != "" {
		cfg.MCIAS.ServerURL = v
	}
	if v := os.Getenv("MCP_MCIAS_CA_CERT"); v != "" {
		cfg.MCIAS.CACert = v
	}
	if v := os.Getenv("MCP_MCIAS_SERVICE_NAME"); v != "" {
		cfg.MCIAS.ServiceName = v
	}
	if v := os.Getenv("MCP_AUTH_TOKEN_PATH"); v != "" {
		cfg.Auth.TokenPath = v
	}
}

func validateCLIConfig(cfg *CLIConfig) error {
	if cfg.Services.Dir == "" {
		return fmt.Errorf("services.dir is required")
	}
	if cfg.MCIAS.ServerURL == "" {
		return fmt.Errorf("mcias.server_url is required")
	}
	if cfg.MCIAS.ServiceName == "" {
		return fmt.Errorf("mcias.service_name is required")
	}
	if cfg.Auth.TokenPath == "" {
		return fmt.Errorf("auth.token_path is required")
	}
	return nil
}
