package manifests

import (
	"fmt"
	"path/filepath"

	"github.com/ghodss/yaml"
	operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1"
	"github.com/pkg/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/openshift/installer/pkg/asset"
	"github.com/openshift/installer/pkg/asset/installconfig"
)

var imageContentSourcePolicyFilenameFormat = "image-content-source-policy-%s.yaml"

// ImageContentSourcePolicy generates the image-content-source-policy.yaml files.
type ImageContentSourcePolicy struct {
	FileList []*asset.File
}

var _ asset.WritableAsset = (*ImageContentSourcePolicy)(nil)

// Name returns a human-friendly name for the asset.
func (*ImageContentSourcePolicy) Name() string {
	return "Image Content Source Policy"
}

// Dependencies returns all of the dependencies directly needed to generate
// the asset.
func (*ImageContentSourcePolicy) Dependencies() []asset.Asset {
	return []asset.Asset{
		&installconfig.InstallConfig{},
	}
}

// Generate generates the ImageContentSourcePolicy config and its CRD.
func (p *ImageContentSourcePolicy) Generate(dependencies asset.Parents) error {
	installconfig := &installconfig.InstallConfig{}
	dependencies.Get(installconfig)

	padFormat := fmt.Sprintf("%%0%dd", len(fmt.Sprintf("%d", len(installconfig.Config.ImageContentSources))))

	var policies []*operatorv1alpha1.ImageContentSourcePolicy
	for gidx, group := range installconfig.Config.ImageContentSources {
		policies = append(policies, &operatorv1alpha1.ImageContentSourcePolicy{
			TypeMeta: metav1.TypeMeta{
				APIVersion: operatorv1alpha1.SchemeGroupVersion.String(),
				Kind:       "ImageContentSourcePolicy",
			},
			ObjectMeta: metav1.ObjectMeta{
				Name: fmt.Sprintf("image-policy-%s", fmt.Sprintf(padFormat, gidx)),
				// not namespaced
			},
			Spec: operatorv1alpha1.ImageContentSourcePolicySpec{
				RepositoryDigestMirrors: []operatorv1alpha1.RepositoryDigestMirrors{{Source: group.Source, Mirrors: group.Mirrors}},
			},
		})
	}

	p.FileList = make([]*asset.File, len(policies))
	for i, policy := range policies {
		policyData, err := yaml.Marshal(policy)
		if err != nil {
			return errors.Wrapf(err, "failed to marshal ImageContentSourcePolicy")
		}
		padded := fmt.Sprintf(padFormat, i)
		p.FileList[i] = &asset.File{
			Filename: filepath.Join(manifestDir, fmt.Sprintf(imageContentSourcePolicyFilenameFormat, padded)),
			Data:     policyData,
		}
	}
	return nil
}

// Files returns the files generated by the asset.
func (p *ImageContentSourcePolicy) Files() []*asset.File {
	return p.FileList
}

// Load loads the already-rendered files back from disk.
func (p *ImageContentSourcePolicy) Load(f asset.FileFetcher) (bool, error) {
	return false, nil
}
