package main

import (
	"os"
	"os/signal"
	"sync"
	"syscall"

	v1 "k8s.io/api/core/v1"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"k8s.io/klog/v2"
)

func getPodInformer() (cache.SharedIndexInformer, error) {
	if config, err := rest.InClusterConfig(); err != nil {
		return nil, err
	} else if clientset, err := kubernetes.NewForConfig(config); err != nil {
		return nil, err
	} else {
		factory := informers.NewSharedInformerFactory(clientset, 0)
		informer := factory.Core().V1().Pods().Informer()

		informer.AddEventHandler(
			cache.ResourceEventHandlerDetailedFuncs{
				AddFunc: func(obj interface{}, isInInitialList bool) {
					pod := obj.(*v1.Pod)
					klog.InfoS("add event - pod", "name", pod.Name, "isInInitialList", isInInitialList)
				},
				UpdateFunc: func(oldObj, newObj interface{}) {
					pod := newObj.(*v1.Pod)
					klog.InfoS("update event - pod", "name", pod.Name)
				},
				DeleteFunc: func(obj interface{}) {
					pod := obj.(*v1.Pod)
					klog.InfoS("delete event - pod", "name", pod.Name)
				},
			})

		return informer, nil
	}
}

func getServiceInformer() (cache.SharedIndexInformer, error) {
	if config, err := rest.InClusterConfig(); err != nil {
		return nil, err
	} else if clientset, err := kubernetes.NewForConfig(config); err != nil {
		return nil, err
	} else {
		factory := informers.NewSharedInformerFactory(clientset, 0)
		informer := factory.Core().V1().Services().Informer()

		informer.AddEventHandler(
			cache.ResourceEventHandlerDetailedFuncs{
				AddFunc: func(obj interface{}, isInInitialList bool) {
					pod := obj.(*v1.Service)
					klog.InfoS("add event - service", "name", pod.Name, "isInInitialList", isInInitialList)
				},
				UpdateFunc: func(oldObj, newObj interface{}) {
					pod := newObj.(*v1.Service)
					klog.InfoS("update event - service", "name", pod.Name)
				},
				DeleteFunc: func(obj interface{}) {
					pod := obj.(*v1.Service)
					klog.InfoS("delete event - service", "name", pod.Name)
				},
			})

		return informer, nil
	}
}

func main() {
	defer klog.Flush()

	klog.InfoS("main start")
	defer klog.InfoS("main end")

	wg := new(sync.WaitGroup)
	stopper := make(chan struct{})

	run := func(getInformer func() (cache.SharedIndexInformer, error)) {
		if informer, err := getInformer(); err != nil {
			klog.ErrorS(err, "")
		} else {
			wg.Add(1)
			go func() {
				defer wg.Done()
				informer.Run(stopper)
			}()
		}
	}

	run(getPodInformer)
	run(getServiceInformer)

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
	<-signals

	close(stopper)
	wg.Wait()
}
