package workdir

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
)

const PluginPathFilename = "plugin_path"

// ProviderLocalCacheDir returns the directory we'll use as the
// working-directory-specific local cache of providers.
//
// The provider installer's job is to make sure that all providers needed for
// a particular working directory are available in this cache directory. No
// other component may write here, and in particular a Dir object itself
// never reads or writes into this directory, instead just delegating all of
// that responsibility to other components.
//
// Typically, the caller will ultimately pass the result of this method either
// directly or indirectly into providercache.NewDir, to get an object
// responsible for managing the contents.
func (d *Dir) ProviderLocalCacheDir() string {
	return filepath.Join(d.dataDir, "providers")
}

// ForcedPluginDirs returns a list of directories to use to find plugins,
// instead of the default locations.
//
// Returns an zero-length list and no error in the normal case where there
// are no overridden search directories. If ForcedPluginDirs returns a
// non-empty list with no errors then the result totally replaces the default
// search directories.
func (d *Dir) ForcedPluginDirs() ([]string, error) {
	raw, err := ioutil.ReadFile(filepath.Join(d.dataDir, PluginPathFilename))
	if os.IsNotExist(err) {
		return nil, nil
	}

	if err != nil {
		return nil, err
	}

	var pluginPath []string
	if err := json.Unmarshal(raw, &pluginPath); err != nil {
		return nil, err
	}
	return pluginPath, nil
}

// SetForcedPluginDirs records an overridden list of directories to search
// to find plugins, instead of the default locations. See ForcePluginDirs
// for more information.
//
// Pass a zero-length list to deactivate forced plugin directories altogether,
// thus allowing the working directory to return to using the default
// search directories.
func (d *Dir) SetForcedPluginDirs(dirs []string) error {

	filePath := filepath.Join(d.dataDir, PluginPathFilename)
	switch {
	case len(dirs) == 0:
		err := os.Remove(filePath)
		if !os.IsNotExist(err) {
			return err
		}
		return nil
	default:
		// We'll ignore errors from this one, because if we fail to create
		// the directory then we'll fail to create the file below too,
		// and that subsequent error will more directly reflect what we
		// are trying to do here.
		d.ensureDataDir()

		raw, err := json.MarshalIndent(dirs, "", "  ")
		if err != nil {
			return err
		}

		return ioutil.WriteFile(filePath, raw, 0644)
	}
}
