package watch_graph //nolint:staticcheck

import (
	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
	sourcev1 "github.com/fluxcd/source-controller/api/v1"
	appsv1 "k8s.io/api/apps/v1"
	autoscalingv1 "k8s.io/api/autoscaling/v1"
	autoscalingv2 "k8s.io/api/autoscaling/v2"
	batchv1 "k8s.io/api/batch/v1"
	certificatesv1alpha1 "k8s.io/api/certificates/v1alpha1"
	corev1 "k8s.io/api/core/v1"
	eventsv1 "k8s.io/api/events/v1"
	networkingv1 "k8s.io/api/networking/v1"
	nodev1 "k8s.io/api/node/v1"
	rbacv1 "k8s.io/api/rbac/v1"
	resourcev1beta1 "k8s.io/api/resource/v1beta1"
	schedulingv1 "k8s.io/api/scheduling/v1"
	storagev1 "k8s.io/api/storage/v1"
	storagev1beta1 "k8s.io/api/storage/v1beta1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
)

var (
	secretGVK                = corev1.SchemeGroupVersion.WithKind("Secret")
	configMapGVK             = corev1.SchemeGroupVersion.WithKind("ConfigMap")
	podGVK                   = corev1.SchemeGroupVersion.WithKind("Pod")
	serviceGVK               = corev1.SchemeGroupVersion.WithKind("Service")
	nodeGVK                  = corev1.SchemeGroupVersion.WithKind("Node")
	replicationControllerGVK = corev1.SchemeGroupVersion.WithKind("ReplicationController")
	serviceAccountGVK        = corev1.SchemeGroupVersion.WithKind("ServiceAccount")
	persistentVolumeClaimGVK = corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim")
	persistentVolumeGVK      = corev1.SchemeGroupVersion.WithKind("PersistentVolume")

	eventGVK = eventsv1.SchemeGroupVersion.WithKind("Event") // use instead of corev1.Event

	deploymentGVK  = appsv1.SchemeGroupVersion.WithKind("Deployment")
	replicaSetGVK  = appsv1.SchemeGroupVersion.WithKind("ReplicaSet")
	daemonSetGVK   = appsv1.SchemeGroupVersion.WithKind("DaemonSet")
	statefulSetGVK = appsv1.SchemeGroupVersion.WithKind("StatefulSet")

	clusterRoleBindingGVK = rbacv1.SchemeGroupVersion.WithKind("ClusterRoleBinding")
	roleBindingGVK        = rbacv1.SchemeGroupVersion.WithKind("RoleBinding")

	jobGVK     = batchv1.SchemeGroupVersion.WithKind("Job")
	cronJobGVK = batchv1.SchemeGroupVersion.WithKind("CronJob")

	hpaV1GVK = autoscalingv1.SchemeGroupVersion.WithKind("HorizontalPodAutoscaler")
	hpaV2GVK = autoscalingv2.SchemeGroupVersion.WithKind("HorizontalPodAutoscaler")

	storageClassGVK                 = storagev1.SchemeGroupVersion.WithKind("StorageClass")
	csiStorageCapacityGVK           = storagev1.SchemeGroupVersion.WithKind("CSIStorageCapacity")
	volumeAttachmentGVK             = storagev1.SchemeGroupVersion.WithKind("VolumeAttachment")
	volumeAttributesClassV1Beta1GVK = storagev1beta1.SchemeGroupVersion.WithKind("VolumeAttributesClass")

	clusterTrustBundleV1Alpha1GVK = certificatesv1alpha1.SchemeGroupVersion.WithKind("ClusterTrustBundle")

	ingressGVK      = networkingv1.SchemeGroupVersion.WithKind("Ingress")
	ingressClassGVK = networkingv1.SchemeGroupVersion.WithKind("IngressClass")

	gatewayGVK      = gatewayapiv1.SchemeGroupVersion.WithKind("Gateway")
	gatewayClassGVK = gatewayapiv1.SchemeGroupVersion.WithKind("GatewayClass")
	httpRouteGVK    = gatewayapiv1.SchemeGroupVersion.WithKind("HTTPRoute")
	grpcRouteGVK    = gatewayapiv1.SchemeGroupVersion.WithKind("GRPCRoute")

	priorityClassGVK = schedulingv1.SchemeGroupVersion.WithKind("PriorityClass")

	runtimeClassGVK = nodev1.SchemeGroupVersion.WithKind("RuntimeClass")

	resourceClaimV1Beta1GVK         = resourcev1beta1.SchemeGroupVersion.WithKind("ResourceClaim")
	resourceClaimTemplateV1Beta1GVK = resourcev1beta1.SchemeGroupVersion.WithKind("ResourceClaimTemplate")

	fluxcdSourceControllerGitRepositoryV1GVK  = sourcev1.GroupVersion.WithKind("GitRepository")
	fluxcdSourceControllerOCIRepositoryV1GVK  = sourcev1.GroupVersion.WithKind("OCIRepository")
	fluxcdSourceControllerHelmRepositoryV1GVK = sourcev1.GroupVersion.WithKind("HelmRepository")
	fluxcdSourceControllerHelmChartV1GVK      = sourcev1.GroupVersion.WithKind("HelmChart")
	fluxcdSourceControllerBucketV1GVK         = sourcev1.GroupVersion.WithKind("Bucket")

	fluxcdKustomizeControllerKustomizationV1GVK = kustomizev1.GroupVersion.WithKind("Kustomization")
)

type vertexGKID struct {
	GK schema.GroupKind
	// The namespace to use if object is namespaced and the source object's namespace should not be used.
	NamespaceOverride string
	Name              string
}

// wgObject2vertex collects vertex and arc data for a Kubernetes object.
// Instances are not reusable.
type wgObject2vertex struct {
	gvr  schema.GroupVersionResource
	info gvrInfo

	// Fields below accumulate results for Get().
	ns       string // empty or namespace of the object
	name     string // name of the object
	arcSet   ArcSetWithData[vertexGKID, ArcType, ArcAttrs]
	warnings []Warning
}

func (vx *wgObject2vertex) Get(obj *unstructured.Unstructured) (VertexData, ArcSetWithData[vertexGKID, ArcType, ArcAttrs], []Warning, *Error) {
	// 1. Must set ns and name first since they are used to construct warnings
	vx.ns = obj.GetNamespace()
	vx.name = obj.GetName()

	// 2. Collect arcs
	err := vx.collectArcs(obj)
	if err != nil {
		return VertexData{}, nil, vx.warnings, err
	}

	// 3. Collect vertex data
	vd := vx.object2vertexData(obj)

	return vd, vx.arcSet, vx.warnings, nil
}

func (vx *wgObject2vertex) appendWarning(warning Warning) {
	vx.warnings = append(vx.warnings, warning)
}

func (vx *wgObject2vertex) appendObjectProcessingWarning(message string) {
	vx.appendWarning(NewObjectProcessingWarning(vx.gvr, vx.ns, vx.name, message))
}
