package main

import (
	"fmt"
	"io/fs"
	"net/url"

	"github.com/osbuild/images/data/repositories"
	"github.com/osbuild/images/pkg/reporegistry"
	"github.com/osbuild/images/pkg/rpmmd"
)

// defaultDataDirs contains the default search paths to look for
// repository data. They contain a bunch of json files of the form
// "$distro_$version".json (but that is an implementation detail that
// the "images" library takes care of).
var defaultDataDirs = []string{
	"/etc/image-builder/repositories",
	"/usr/share/image-builder/repositories",
}

type repoConfig struct {
	DataDir    string
	ExtraRepos []string
}

func parseRepoURLs(repoURLs []string, what string) ([]rpmmd.RepoConfig, error) {
	var repoConf []rpmmd.RepoConfig

	for i, repoURL := range repoURLs {
		// We want to eventually support more URIs repos here:
		// - config:/path/to/repo.json
		// - copr:@osbuild/osbuild (with full gpg retrival via the copr API)
		// But for now just default to base-urls

		baseURL, err := url.Parse(repoURL)
		if err != nil {
			return nil, fmt.Errorf("cannot parse extra repo %w", err)
		}
		if baseURL.Scheme == "" {
			return nil, fmt.Errorf(`scheme missing in %q, please prefix with e.g. file:// or https://`, repoURL)
		}

		// TODO: to support gpg checking we will need to add signing keys.
		// We will eventually add support for our own "repo.json" format
		// which is rich enough to contain gpg keys (and more).
		checkGPG := false
		repoConf = append(repoConf, rpmmd.RepoConfig{
			Id:           fmt.Sprintf("%s-repo-%v", what, i),
			Name:         fmt.Sprintf("%s repo#%v %s%s", what, i, baseURL.Host, baseURL.Path),
			BaseURLs:     []string{baseURL.String()},
			CheckGPG:     &checkGPG,
			CheckRepoGPG: &checkGPG,
		})
	}

	return repoConf, nil
}

func newRepoRegistryImpl(dataDir string, extraRepos []string) (*reporegistry.RepoRegistry, error) {
	var dataDirs []string
	if dataDir != "" {
		dataDirs = []string{dataDir}
	} else {
		dataDirs = defaultDataDirs
	}

	conf, err := reporegistry.LoadAllRepositories(dataDirs, []fs.FS{repos.FS})
	if err != nil {
		return nil, err
	}

	// Add extra repos to all architecture. We support
	// cross-building but at this level here we don't know yet
	// what manifests will be generated so we must (for now)
	// rely on the user to DTRT with extraRepos.
	//
	// XXX: this should probably go into manifestgen.Options as a
	// new Options.ExtraRepoConf eventually (just like
	// OverrideRepos)
	repoConf, err := parseRepoURLs(extraRepos, "extra")
	if err != nil {
		return nil, err
	}
	for _, repoArchConfigs := range conf {
		for arch := range repoArchConfigs {
			archCfg := repoArchConfigs[arch]
			archCfg = append(archCfg, repoConf...)
			repoArchConfigs[arch] = archCfg
		}
	}

	return reporegistry.NewFromDistrosRepoConfigs(conf), nil
}

// this is a variable to make it overridable in tests
var newRepoRegistry = newRepoRegistryImpl
