package config

import (
	"errors"

	"github.com/go-playground/validator"
	"github.com/imdario/mergo"
	confLoader "github.com/otakukaze/config-loader"
)

type Config struct {
	Server Server `yaml:"server"`
}

type Server struct {
	Port   int    `yaml:"port" env:"SERVER_PORT" default:"10230" validate:"gte=1,lte=65535"`
	Secret string `yaml:"secret" env:"SERVER_SECRET" default:"lawsnote-rpi" validate:"required,min=1"`

	RelayPin int `yaml:"relay_pin" env:"SERVER_RELAY_PIN" validate:"required,gte=1,lte=255"`
}

func Load(cfgPath ...string) (*Config, error) {
	cfg := &Config{}

	// load config from env and default value
	if err := confLoader.Load(cfg, &confLoader.LoadOptions{FromEnv: true}); err != nil {
		return nil, err
	}

	validate := validator.New()
	if len(cfgPath) > 0 {

		for _, v := range cfgPath {
			fileOpts := &confLoader.ConfigFile{Type: confLoader.ConfigFileTypeYAML, Path: v}
			loadOpts := &confLoader.LoadOptions{ConfigFile: fileOpts, FromEnv: false}

			c := &Config{}

			if err := confLoader.Load(c, loadOpts); err != nil {
				return nil, err
			}

			// validate struct fields
			if err := validate.Struct(c); err != nil {
				return nil, err
			}

			// merge new config to prev config withOverride
			if err := mergo.Merge(&cfg, c, mergo.WithOverride); err != nil {
				return nil, err
			}
		}

	}

	if cfg.Server.RelayPin < 1 || cfg.Server.RelayPin > 255 {
		return nil, errors.New("gpio pin range wrong (1 <= x <= 255)")
	}

	if cfg.Server.Secret == "" {
		return nil, errors.New("secret empty")
	}

	return cfg, nil
}
