package registrymirror

import (
	"net"
	urllib "net/url"
	"path/filepath"
	"strings"

	"github.com/aws/eks-anywhere/pkg/api/v1alpha1"
	"github.com/aws/eks-anywhere/pkg/constants"
)

// RegistryMirror configures mirror mappings for artifact registries.
type RegistryMirror struct {
	// BaseRegistry is the address of the registry mirror without namespace. Just the host and the port.
	BaseRegistry string
	// NamespacedRegistryMap stores mirror mappings for artifact registries
	NamespacedRegistryMap map[string]string
	// Auth should be marked as true if authentication is required for the registry mirror
	Auth bool
	// CACertContent defines the contents registry mirror CA certificate
	CACertContent string
	// InsecureSkipVerify skips the registry certificate verification.
	// Only use this solution for isolated testing or in a tightly controlled, air-gapped environment.
	InsecureSkipVerify bool
}

// FromCluster is a constructor for RegistryMirror from a cluster schema.
func FromCluster(cluster *v1alpha1.Cluster) *RegistryMirror {
	return FromClusterRegistryMirrorConfiguration(cluster.Spec.RegistryMirrorConfiguration)
}

// FromClusterRegistryMirrorConfiguration is a constructor for RegistryMirror from a RegistryMirrorConfiguration schema.
func FromClusterRegistryMirrorConfiguration(config *v1alpha1.RegistryMirrorConfiguration) *RegistryMirror {
	if config == nil {
		return nil
	}
	registryMap := make(map[string]string)
	base := net.JoinHostPort(config.Endpoint, config.Port)
	// add registry mirror base address
	// for each namespace, add corresponding endpoint
	for _, ociNamespace := range config.OCINamespaces {
		mirror := filepath.Join(base, ociNamespace.Namespace)
		registryMap[ociNamespace.Registry] = mirror
	}
	if len(registryMap) == 0 {
		// for backward compatibility, default mapping for public.ecr.aws is added
		// when no namespace mapping is specified
		registryMap[constants.DefaultCoreEKSARegistry] = base
	}
	return &RegistryMirror{
		BaseRegistry:          base,
		NamespacedRegistryMap: registryMap,
		Auth:                  config.Authenticate,
		CACertContent:         config.CACertContent,
		InsecureSkipVerify:    config.InsecureSkipVerify,
	}
}

// CoreEKSAMirror returns the configured mirror for public.ecr.aws.
func (r *RegistryMirror) CoreEKSAMirror() string {
	return r.NamespacedRegistryMap[constants.DefaultCoreEKSARegistry]
}

// ReplaceRegistry replaces the host in a url with corresponding registry mirror
// It supports full URLs and container image URLs
// If the provided original url is malformed, there are no guarantees
// that the returned value will be valid
// If no corresponding registry mirror, it will return the original URL.
func (r *RegistryMirror) ReplaceRegistry(url string) string {
	if r == nil {
		return url
	}

	u, _ := urllib.Parse(url)
	if u.Scheme == "" {
		u, _ = urllib.Parse("oci://" + url)
		u.Scheme = ""
	}
	key := u.Host
	if v, ok := r.NamespacedRegistryMap[key]; ok {
		return strings.Replace(url, u.Host, v, 1)
	}
	return url
}
