package config

import (
	"fmt"
	"io/ioutil"

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

// GRPC contains the gRPC-specific configuration options
type GRPC struct {
	Port string `toml:"port"`
}

// REST contains the REST-specific configuration options
type REST struct {
	ExternalPort string `toml:"externalPort"`
}

// Inspector contains the Inspector URL configuration
type Inspector struct {
	InspectorURL string `toml:"inspectorUrl"`
}

// Logger contains the logging-specific configuration options
type Logger struct {
	Level  string `toml:"level"`
	Output string `toml:"output"`
	Format string `toml:"format"`
}

// Monitor contains the monitoring-specific configuration options
type Monitor struct {
	Address string `toml:"address"`
}

type ExtraAttributes struct {
	MonitorMode string `toml:"monitorMode"`
}

type Filter struct {
	AllowList map[string]string `toml:"allowList"`
	DenyList  map[string]string `toml:"denyList"`
}

// Config is configuration for Server
type Config struct {
	GRPC            GRPC
	REST            REST
	Logger          Logger
	Monitor         Monitor
	Inspector       Inspector
	ExtraAttributes ExtraAttributes
	Filter          Filter
}

// LoadConfig Loads a TOML file from the path into this Config object
func (config *Config) LoadConfig(path string) error {
	tomlFile, err := ioutil.ReadFile(path)
	if err != nil {
		return fmt.Errorf("reading config file :%w", err)
	}

	return toml.Unmarshal(tomlFile, config)
}

func RunConfig() (*Config, error) {
	return RunConfigWithConfigFile("config/config.toml")
}

// RunConfig calls the LoadConfig function & returns errors if any
func RunConfigWithConfigFile(configPath string) (*Config, error) {
	// get configuration
	var cfg Config

	err := cfg.LoadConfig(configPath)

	if err != nil {
		return nil, fmt.Errorf("RunConfig(): Error loading configuration: %s", err)
	}

	err = ValidateConfig(&cfg)

	if err != nil {
		return nil, fmt.Errorf("RunConfig(): Error validating configuration: %s", err)
	}

	return &cfg, err
}

func ValidateConfig(cfg *Config) error {
	if len(cfg.GRPC.Port) == 0 {
		return fmt.Errorf("invalid TCP port for gRPC server: '%s'", cfg.GRPC.Port)
	}

	if len(cfg.REST.ExternalPort) == 0 {
		return fmt.Errorf("invalid TCP port for HTTP gateway: '%s'", cfg.REST.ExternalPort)
	}

	if len(cfg.Filter.AllowList) != 0 && len(cfg.Filter.DenyList) != 0 {
		return fmt.Errorf("Both allowlist & denylist cannot have items at the same time")
	}

	return nil
}
