// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0

package gvk

import (
	"fmt"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

type TenantResourceID struct {
	Tenant string `json:"tenant,omitempty"`
}

type TenantResourceIDWithOrigin struct {
	TenantResourceID `json:",inline"`

	Origin string `json:"origin,omitempty"`
}

// ResourceID represents the decomposed parts of a Kubernetes resource identity.
type ResourceID struct {
	TenantResourceIDWithOrigin `json:",inline"`

	Group     string `json:"group,omitempty"`
	Version   string `json:"version,omitempty"`
	Kind      string `json:"kind,omitempty"`
	Name      string `json:"name,omitempty"`
	Namespace string `json:"namespace,omitempty"`
}

// ResourceKey builds the canonical key string used for maps/sets.
// Non-namespaced objects will have "_" as the namespace component.
func NewResourceID(u *unstructured.Unstructured, tenant string, origin string) ResourceID {
	gvk := u.GroupVersionKind()

	return ResourceID{
		Group:     gvk.Group,
		Version:   gvk.Version,
		Kind:      gvk.Kind,
		Name:      u.GetName(),
		Namespace: u.GetNamespace(),
		TenantResourceIDWithOrigin: TenantResourceIDWithOrigin{
			TenantResourceID: TenantResourceID{
				Tenant: tenant,
			},
			Origin: origin,
		},
	}
}

func (r ResourceID) GetName() string {
	return r.Name
}

func (r ResourceID) GetNamespace() string {
	return r.Namespace
}

// GVK returns the schema.GroupVersionKind of the resource.
func (r ResourceID) GetGVK() schema.GroupVersionKind {
	return schema.GroupVersionKind{
		Group:   r.Group,
		Version: r.Version,
		Kind:    r.Kind,
	}
}

func (r ResourceID) GetGVKKey(sep string) string {
	if sep == "" {
		sep = "\x1f"
	}

	return fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s",
		r.Group, sep,
		r.Version, sep,
		r.Kind, sep,
		r.Namespace, sep,
		r.Name, sep,
	)
}

func (r ResourceID) GetKey(sep string) string {
	// Use a delimiter that won’t appear in fields normally; '\x1f' (unit separator) is great.
	if sep == "" {
		sep = "\x1f"
	}

	return fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
		r.Group, sep,
		r.Version, sep,
		r.Kind, sep,
		r.Namespace, sep,
		r.Name, sep,
		r.Tenant, sep,
		r.Origin, sep,
	)
}

func (r ResourceID) FieldOwner(sep string) string {
	// Use a delimiter that won’t appear in fields normally; '\x1f' (unit separator) is great.
	if sep == "" {
		sep = "/"
	}

	return fmt.Sprintf("%s%s%s%s%s%s",
		r.Namespace, sep,
		r.Tenant, sep,
		r.Origin, sep,
	)
}
