package interchange

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
)

const (
	// EnvName is the OS Environment Variable specifying where the forerunner
	// data file will loaded from.
	EnvName = "FORERUNNER_INTERCHANGE"
	// Version is the current version of the forerunner data file.
	Version = "0.3.0"
)

type EntrySet map[string]*ConfigEntry
type Source string

const (
	ENV     Source = "env"
	Flags          = "flags"
	Config         = "config"
	Consul         = "consul"
	Vault          = "vault"
	Default        = "default"
)

type Interchange struct {
	Version string
	Entries map[string]*ConfigEntry
}

type ConfigEntry struct {
	Value  interface{}
	Source Source
	Secret bool
}

// LoadInterchange will load the config and return the location of a processed
// output.
func LoadInterchange(appName, environment string, consulEntries, vaultEntries map[string]*ConfigEntry) (string, error) {
	if appName == "" || environment == "" {
		return "", fmt.Errorf("Invalid arguments to LoadInterchange")
	}

	f, err := ioutil.TempFile("", appName)
	if err != nil {
		return "", nil
	}

	// TODO:
	//
	// * load config file vars
	config := &Interchange{
		Version: Version,
		Entries: merge(
			nil,
			vaultEntries,
			consulEntries,
		),
	}

	err = json.NewEncoder(f).Encode(&config)
	if err != nil {
		return "", err
	}

	if err := f.Sync(); err != nil {
		return "", err
	}

	return f.Name(), nil
}

func merge(configVars, vaultEntries, consulVars map[string]*ConfigEntry) map[string]*ConfigEntry {
	res := map[string]*ConfigEntry{}
	for _, entries := range []map[string]*ConfigEntry{
		// These are in order from least to most important to merge correctly!
		consulVars,
		vaultEntries,
		configVars,
	} {
		for k, v := range entries {
			res[k] = v
		}
	}

	return res
}
