package cmd

import (
	"bytes"
	"os"
	"path/filepath"

	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v3"
	"go.yaml.in/yaml/v3"
)

const (
	FlagConfig = "config"
)

func ConfigFlags(defaultValue string) []cli.Flag {
	return []cli.Flag{
		&cli.StringFlag{
			Name:    FlagConfig,
			Aliases: []string{"c"},
			Usage:   "Configuration file path",
			Value:   defaultValue,
		},
	}
}

type ConfigWithIncludes interface {
	Includes() []string
}

func Load(logger *logrus.Logger, name string, config ConfigWithIncludes, parsed ...string) (err error) {
	if !filepath.IsAbs(name) {
		var abs string
		if abs, err = filepath.Abs(name); err != nil {
			return
		}
		logger.Tracef("config: canonicallize %s => %s", name, abs)
		name = abs
	}

	logger.Tracef("config: parsed %s", parsed)
	logger.Debugf("config: parse %s", name)
	var data []byte
	if data, err = os.ReadFile(name); err != nil {
		return
	}

	decoder := yaml.NewDecoder(bytes.NewBuffer(data))
	decoder.KnownFields(true)
	if err = decoder.Decode(config); err != nil {
		return err
	}

	for _, include := range config.Includes() {
		if contains(parsed, include) {
			continue
		}
		if !filepath.IsAbs(include) {
			abs := filepath.Clean(filepath.Join(filepath.Dir(name), include))
			logger.Tracef("config: canonicallize %s => %s", include, abs)
			include = abs
		}
		parsed = append(parsed, include)
		if err = Load(logger, include, config, parsed...); err != nil {
			return
		}
	}

	return nil
}

func contains(ss []string, s string) bool {
	for _, v := range ss {
		if v == s {
			return true
		}
	}
	return false
}
