package config

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

	"coopcloud.tech/abra/pkg/log"
	"gopkg.in/yaml.v3"
)

// LoadAbraConfig returns the abra configuration. It tries to find a abra
// configuration file (see findAbraConfig for lookup logic). When no
// configuration was found it returns the default config.
func LoadAbraConfig() Abra {
	wd, _ := os.Getwd()
	configFile := findAbraConfig(wd)
	if configFile == "" {
		log.Debugf("no config file found")
		return Abra{}
	}
	data, err := os.ReadFile(configFile)
	if err != nil {
		// Do nothing, when an error occurs
		log.Debugf("error reading config file: %s", err)
		return Abra{}
	}

	config := Abra{}
	err = yaml.Unmarshal(data, &config)
	if err != nil {
		// Do nothing, when an error occurs
		log.Debugf("error loading config file: %s", err)
		return Abra{}
	}
	log.Debugf("config file loaded from: %s", configFile)
	config.configPath = configFile
	return config
}

// findAbraConfig recursively looks for a abra.y(a)ml file in the given directory.
// When the file was not found it calls the function again with the parent
// directory until the home directory is hit. When no abra config was found it
// returns an empty string.
func findAbraConfig(dir string) string {
	dir, err := filepath.Abs(dir)
	if err != nil {
		return ""
	}
	if dir == os.ExpandEnv("$HOME") || dir == "/" {
		return ""
	}
	p := path.Join(dir, "abra.yaml")
	if _, err := os.Stat(p); err == nil {
		return p
	}
	p = path.Join(dir, "abra.yml")
	if _, err := os.Stat(p); err == nil {
		return p
	}
	return findAbraConfig(filepath.Dir(dir))
}

// Abra defines the configuration file for abra.
type Abra struct {
	configPath string
	AbraDir    string `yaml:"abraDir"`
}

// GetAbraDir returns the abra dir. It has the following logic:
// 1. check if $ABRA_DIR is set
// 2. check if abraDir was set in a config file
// 3. use $HOME/.abra when above two options failed
func (a Abra) GetAbraDir() string {
	if dir, exists := os.LookupEnv("ABRA_DIR"); exists && dir != "" {
		log.Debug("read abra dir from $ABRA_DIR")
		return dir
	}
	if a.AbraDir != "" {
		log.Debug("read abra dir from config file")
		if path.IsAbs(a.AbraDir) {
			return a.AbraDir
		}
		// Make the path absolute
		return path.Join(a.configPath, a.AbraDir)
	}
	log.Debug("using default abra dir")
	return os.ExpandEnv("$HOME/.abra")
}

var config = LoadAbraConfig()

var (
	ABRA_DIR                 = config.GetAbraDir()
	SERVERS_DIR              = path.Join(ABRA_DIR, "servers")
	RECIPES_DIR              = path.Join(ABRA_DIR, "recipes")
	VENDOR_DIR               = path.Join(ABRA_DIR, "vendor")
	BACKUP_DIR               = path.Join(ABRA_DIR, "backups")
	CATALOGUE_DIR            = path.Join(ABRA_DIR, "catalogue")
	RECIPES_JSON             = path.Join(ABRA_DIR, "catalogue", "recipes.json")
	REPOS_BASE_URL           = "https://git.coopcloud.tech/coop-cloud"
	CATALOGUE_JSON_REPO_NAME = "recipes-catalogue-json"
	SSH_URL_TEMPLATE         = "ssh://git@git.coopcloud.tech:2222/coop-cloud/%s.git"
)