package main

import (
	"context"
	"fmt"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	clientgofake "k8s.io/client-go/kubernetes/fake"
	"sigs.k8s.io/controller-runtime/pkg/client"
	runtimefake "sigs.k8s.io/controller-runtime/pkg/client/fake"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

type Reconciler struct{ Client client.Client }

func (r Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
	var cm corev1.ConfigMap
	if err := r.Client.Get(ctx, req.NamespacedName, &cm); err != nil {
		if apierrors.IsNotFound(err) {
			return reconcile.Result{}, nil
		}
		return reconcile.Result{}, err
	}
	if cm.Data["managed"] == "true" {
		return reconcile.Result{}, nil
	}
	if cm.Data == nil {
		cm.Data = map[string]string{}
	}
	cm.Data["managed"] = "true"
	return reconcile.Result{}, r.Client.Update(ctx, &cm)
}

type countingClient struct {
	client.Client
	updates int
}

func (c *countingClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
	c.updates++
	return c.Client.Update(ctx, obj, opts...)
}
func main() {
	ctx := context.Background()
	cm := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "demo"}, Data: map[string]string{"owner": "team"}}
	cs := clientgofake.NewClientset(cm.DeepCopy())
	list, err := cs.CoreV1().ConfigMaps("demo").List(ctx, metav1.ListOptions{})
	if err != nil {
		panic(err)
	}
	fmt.Println("client-go fake: configmaps=", len(list.Items))
	scheme := runtime.NewScheme()
	if err := corev1.AddToScheme(scheme); err != nil {
		panic(err)
	}
	c := &countingClient{Client: runtimefake.NewClientBuilder().WithScheme(scheme).WithObjects(cm.DeepCopy()).Build()}
	r := Reconciler{Client: c}
	req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "demo", Name: "app"}}
	for range 2 {
		if _, err := r.Reconcile(ctx, req); err != nil {
			panic(err)
		}
	}
	var got corev1.ConfigMap
	if err := c.Get(ctx, req.NamespacedName, &got); err != nil {
		panic(err)
	}
	fmt.Printf("two reconciles: updates=%d managed=%s owner=%s\n", c.updates, got.Data["managed"], got.Data["owner"])
}
