/*
Copyright 2017 The Kubernetes Authors.
Copyright 2017-2025 The Volcano Authors.

Modifications made by Volcano authors:
- Extended cache interface with enhanced binding, client access and metrics support
- Added new interfaces for pre-binding, batch binding and status updating

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cache

import (
	"context"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/record"
	fwk "k8s.io/kube-scheduler/framework"

	vcclient "volcano.sh/apis/pkg/client/clientset/versioned"
	vcinformer "volcano.sh/apis/pkg/client/informers/externalversions"
	agentapi "volcano.sh/volcano/pkg/agentscheduler/api"
	"volcano.sh/volcano/pkg/scheduler/api"
	k8sutil "volcano.sh/volcano/pkg/scheduler/plugins/util/k8s"
	k8sschedulingqueue "volcano.sh/volcano/third_party/kubernetes/pkg/scheduler/backend/queue"
)

// Cache collects pods/nodes/queues information
// and provides information snapshot
type Cache interface {
	// Run start informer
	Run(stopCh <-chan struct{})

	// Snapshot deep copy overall cache information into snapshot
	Snapshot() *api.ClusterInfo

	// WaitForCacheSync waits for all cache synced
	WaitForCacheSync(stopCh <-chan struct{})

	// AddBindTask binds Task to the target host.
	// TODO(jinzhej): clean up expire Tasks.
	AddBindTask(bindCtx *agentapi.BindContext) error

	// RecordCandidateNodesInBinder records candidate nodes to be checked in binder and these nodes are waiting to be checked in binder.
	RecordCandidateNodesInBinder(nodes []*api.NodeInfo)

	RemoveCandidateNodesFromBinder(nodes []*api.NodeInfo)

	// Client returns the kubernetes clientSet, which can be used by plugins
	Client() kubernetes.Interface

	// VCClient returns the volcano clientSet, which can be used by plugins
	VCClient() vcclient.Interface

	// ClientConfig returns the rest config
	ClientConfig() *rest.Config

	UpdateSchedulerNumaInfo(sets map[string]api.ResNumaSets) error

	// SharedInformerFactory return scheduler SharedInformerFactory
	SharedInformerFactory() informers.SharedInformerFactory

	// SharedInformerFactory return scheduler vc SharedInformerFactory
	VCSharedInformerFactory() vcinformer.SharedInformerFactory

	// SetMetricsConf set the metrics server related configuration
	SetMetricsConf(conf map[string]string)

	// EventRecorder returns the event recorder
	EventRecorder() record.EventRecorder

	// RegisterBinder registers the passed binder to the cache's binderRegistry
	RegisterBinder(name string, binder interface{})

	// SharedDRAManager returns the shared DRAManager
	SharedDRAManager() fwk.SharedDRAManager

	// UpdateSnapshot is used to update the passed-in snapshot to ensure consistency between the cache's nodeinfo and the snapshot.
	UpdateSnapshot(snapshot *k8sutil.Snapshot) error

	// TaskUnschedulable update pod unschedulable status
	TaskUnschedulable(task *api.TaskInfo, reason, message string) error

	// EnqueueScheduleResult put result into binder check queue
	EnqueueScheduleResult(result *agentapi.PodScheduleResult)

	// SchedulingQueue returns the scheduling queue instance in the cache
	SchedulingQueue() k8sschedulingqueue.SchedulingQueue

	// GetTaskInfo returns the TaskInfo from the cache with the given taskID.
	GetTaskInfo(taskID api.TaskID) (*api.TaskInfo, bool)

	//UpdateNodeShardStatus update status in nodeshard
	UpdateNodeShardStatus(shardName string, usedNodeInCache sets.Set[string]) error

	// OnWorkerStartSchedulingCycle is called when scheduler worker start a new scheduling cycle
	OnWorkerStartSchedulingCycle(index int, schedCtx *agentapi.SchedulingContext)

	// OnWorkerEndSchedulingCycle is called when scheduler worker end a scheduling cycle
	OnWorkerEndSchedulingCycle(index int)
}

// Binder interface for binding task and hostname
type Binder interface {
	Bind(kubeClient kubernetes.Interface, tasks []*api.TaskInfo) map[api.TaskID]string
}

// StatusUpdater updates pod with given PodCondition
type StatusUpdater interface {
	UpdatePodStatus(pod *v1.Pod) (*v1.Pod, error)
}

type PreBinder interface {
	PreBind(ctx context.Context, bindCtx *agentapi.BindContext) error

	// PreBindRollBack is called when the pre-bind or bind fails.
	PreBindRollBack(ctx context.Context, bindCtx *agentapi.BindContext)
}
