package main

import (
	"context"
	"flag"
	"io/fs"
	"os"
	"path/filepath"

	"github.com/tidwall/gjson"
	"gopkg.in/yaml.v2"
	v1 "k8s.io/api/core/v1"
	k8serr "k8s.io/apimachinery/pkg/api/errors"
	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/util/retry"
)

var (
	dashboardsPath string
	isInternal     bool
)

func main() {
	flag.StringVar(&dashboardsPath, "p", "/clinic/dashboard", "path to the grafana provisioning dashboards")
	flag.BoolVar(&isInternal, "internal", false, "is internal grafana")
	flag.Parse()

	cfg, err := rest.InClusterConfig()
	if err != nil {
		panic(err)
	}

	cli, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		panic(err)
	}

	fis, err := os.ReadDir(dashboardsPath)
	if err != nil {
		panic(err)
	}

	uidMaps := make(map[string][]byte)
	for _, fi := range fis {
		if !fi.IsDir() {
			continue
		}

		uidMap := make(map[string]string)
		filepath.WalkDir(filepath.Join(dashboardsPath, fi.Name()), func(fname string, d fs.DirEntry, err error) error {
			if err != nil {
				panic(err)
			}
			if d.IsDir() {
				return nil
			}

			//data := make(dashboardsData)
			bs, err := os.ReadFile(fname)
			if err != nil {
				panic(err)
			}

			uidMap[gjson.Get(string(bs), "uid").Str] = gjson.Get(string(bs), "title").Str
			return nil
		})

		data, err := yaml.Marshal(uidMap)
		if err != nil {
			panic(err)
		}
		uidMaps[fi.Name()] = data
	}

	cmName := "dashboard-external"
	if isInternal {
		cmName = "dashboard-internal"
	}

	cm := &v1.ConfigMap{
		ObjectMeta: v12.ObjectMeta{
			Name:      cmName,
			Namespace: os.Getenv("NAMESPACE"),
		},
		BinaryData: uidMaps,
	}

	err = createOrUpdateConfigMap(cli, cm)
	if err != nil {
		panic(err)
	}
}

func createOrUpdateConfigMap(cli *kubernetes.Clientset, cm *v1.ConfigMap) error {
	return retry.RetryOnConflict(retry.DefaultRetry, func() error {
		_, err := cli.CoreV1().ConfigMaps(cm.Namespace).Get(context.TODO(), cm.Name, v12.GetOptions{})
		if err != nil {
			if !k8serr.IsNotFound(err) {
				return err
			}

			_, err := cli.CoreV1().ConfigMaps(cm.Namespace).Create(context.TODO(), cm, v12.CreateOptions{})
			return err
		}

		_, err = cli.CoreV1().ConfigMaps(cm.Namespace).Update(context.TODO(), cm, v12.UpdateOptions{})
		return err
	})
}
