package tidbservertemplate

import (
	"context"
	"fmt"

	"github.com/go-logr/logr"
	"github.com/tidbcloud/aws-shared-provider/pkg/manager"
	"github.com/tidbcloud/aws-shared-provider/pkg/tidbmanager"
	"github.com/tidbcloud/aws-shared-provider/pkg/types"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/utils/ptr"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/event"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/predicate"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

// Reconciler reconciles a tidbServerTemplate ConfigMap object.
type Reconciler struct {
	controller.Controller
	logr.Logger

	Client      client.Client
	TidbManager tidbmanager.TidbManager
	Namespace   string
}

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
func (r *Reconciler) Reconcile(_ context.Context, _ ctrl.Request) (ctrl.Result, error) {
	return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *Reconciler) SetupWithManager(mgr manager.Manager) error {
	c, err := controller.New("Tidb-Server-Template-"+r.Namespace, mgr, controller.Options{
		Reconciler:         r,
		NeedLeaderElection: ptr.To(false),
	})
	if err != nil {
		return fmt.Errorf("can't new a controller: %w", err)
	}
	r.Controller = c
	r.Logger = c.GetLogger()

	if err := c.Watch(
		source.Kind(mgr.GetCache(), &corev1.ConfigMap{},
			&handler.TypedEnqueueRequestForObject[*corev1.ConfigMap]{},
			&predicate.TypedFuncs[*corev1.ConfigMap]{ // all funcs return false, because we ignore Reconcile
				CreateFunc: func(createEvent event.TypedCreateEvent[*corev1.ConfigMap]) bool {
					if createEvent.Object.GetNamespace() == r.Namespace &&
						createEvent.Object.GetName() == types.TidbServerPodTemplateCm {
						if createEvent.Object.GetAnnotations()[types.AnnoTidbScalerLock] != "" {
							r.Logger.V(1).Info("CreateFunc: LockFreeCache")
							r.TidbManager.LockFreeCache()
						} else {
							r.Logger.V(1).Info("CreateFunc: UnlockFreeCache")
							r.TidbManager.UnlockFreeCache()
						}
					}
					return false
				},
				UpdateFunc: func(updateEvent event.TypedUpdateEvent[*corev1.ConfigMap]) bool {
					if updateEvent.ObjectNew.GetNamespace() == r.Namespace &&
						updateEvent.ObjectNew.GetName() == types.TidbServerPodTemplateCm {
						if updateEvent.ObjectNew.GetAnnotations()[types.AnnoTidbScalerLock] != "" {
							r.Logger.V(1).Info("UpdateFunc: LockFreeCache")
							r.TidbManager.LockFreeCache()
						} else {
							r.Logger.V(1).Info("UpdateFunc: UnlockFreeCache")
							r.TidbManager.UnlockFreeCache()
						}
					}
					return false
				},
				DeleteFunc: func(deleteEvent event.TypedDeleteEvent[*corev1.ConfigMap]) bool {
					if deleteEvent.Object.GetNamespace() == r.Namespace &&
						deleteEvent.Object.GetName() == types.TidbServerPodTemplateCm {
						r.Logger.V(1).Info("DeleteFunc: UnlockFreeCache")
						r.TidbManager.UnlockFreeCache()
					}
					return false
				},
			})); err != nil {
		return fmt.Errorf("can't watch tidbServerTemplate ConfigMap: %w", err)
	}

	return nil
}
