package operators

import (
	"sort"
	"strings"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// OperatorGroupKind is the PascalCase name of an OperatorGroup's kind.
const OperatorGroupKind = "OperatorGroup"

const (
	OperatorGroupAnnotationKey             = "olm.operatorGroup"
	OperatorGroupNamespaceAnnotationKey    = "olm.operatorNamespace"
	OperatorGroupTargetsAnnotationKey      = "olm.targetNamespaces"
	OperatorGroupProvidedAPIsAnnotationKey = "olm.providedAPIs"
)

// OperatorGroupSpec is the spec for an OperatorGroup resource.
type OperatorGroupSpec struct {
	// Selector selects the OperatorGroup's target namespaces.
	// +optional
	Selector *metav1.LabelSelector

	// TargetNamespaces is an explicit set of namespaces to target.
	// If it is set, Selector is ignored.
	// +optional
	TargetNamespaces []string

	// ServiceAccountName is the admin specified service account which will be
	// used to deploy operator(s) in this operator group.
	ServiceAccountName string

	// Static tells OLM not to update the OperatorGroup's providedAPIs annotation
	// +optional
	StaticProvidedAPIs bool
}

// OperatorGroupStatus is the status for an OperatorGroupResource.
type OperatorGroupStatus struct {
	// Namespaces is the set of target namespaces for the OperatorGroup.
	Namespaces []string

	// ServiceAccountRef references the service account object specified.
	ServiceAccountRef *corev1.ObjectReference

	// LastUpdated is a timestamp of the last time the OperatorGroup's status was Updated.
	LastUpdated *metav1.Time
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +genclient

// OperatorGroup is the unit of multitenancy for OLM managed operators.
// It constrains the installation of operators in its namespace to a specified set of target namespaces.
type OperatorGroup struct {
	metav1.TypeMeta
	metav1.ObjectMeta

	Spec   OperatorGroupSpec
	Status OperatorGroupStatus
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// OperatorGroupList is a list of OperatorGroup resources.
type OperatorGroupList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []OperatorGroup
}

func (o *OperatorGroup) BuildTargetNamespaces() string {
	sort.Strings(o.Status.Namespaces)
	return strings.Join(o.Status.Namespaces, ",")
}
