package main

import (
	"encoding/csv"
	"gopkg.in/yaml.v3"
	"io/ioutil"
	"os"
	"strings"
	"time"
)

type RuleGroups struct {
	Groups []RuleGroup `yaml:"groups"`
}

type RuleGroup struct {
	Name     string        `yaml:"name"`
	Interval time.Duration `yaml:"interval,omitempty"`
	Rules    []Rule        `yaml:"rules"`
}

// Rule describes an alerting or recording rule.
type Rule struct {
	Record      string            `yaml:"record,omitempty"`
	Alert       string            `yaml:"alert,omitempty"`
	Expr        string            `yaml:"expr"`
	For         time.Duration     `yaml:"for,omitempty"`
	Labels      map[string]string `yaml:"labels,omitempty"`
	Annotations map[string]string `yaml:"annotations,omitempty"`
}

func main() {
	groups, err := visit("../../rules")
	if err != nil {
		panic(err)
	}
	f, err := os.OpenFile("../../rules.csv", os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		panic(err)
	}
	// Name,Component,Severity,Desc,for,expr
	csvW := csv.NewWriter(f)
	for _, g := range groups {
		for _, r := range g.Rules {
			if r.Record != "" {
				continue
			}
			err = csvW.Write([]string{
				r.Alert,
				fallback(r.Labels, "component", "alerttype"),
				fallback(r.Labels, "severity"),
				fallback(r.Annotations, "summary", "message", "description"),
				r.For.String(),
				r.Expr,
			})
			if err != nil {
				panic(err)
			}
		}
	}
	csvW.Flush()
}

func fallback(ls map[string]string, keys ...string) string {
	for _, k := range keys {
		if v, ok := ls[k]; ok {
			return v
		}
	}
	return ""
}

func visit(dir string) ([]RuleGroup, error) {
	fis, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, err
	}
	var groups []RuleGroup
	for _, fi := range fis {
		if fi.IsDir() {
			gs, err := visit(dir + "/" + fi.Name())
			if err != nil {
				return nil, err
			}
			groups = append(groups, gs...)
		} else if strings.HasSuffix(fi.Name(), ".yaml") || strings.HasSuffix(fi.Name(), ".yml") {
			content, err := ioutil.ReadFile(dir + "/" + fi.Name())
			if err != nil {
				return nil, err
			}
			gs, err := parse(content)
			if err != nil {
				return nil, err
			}
			groups = append(groups, gs...)
		}
	}
	return groups, nil
}

func parse(s []byte) ([]RuleGroup, error) {
	var c RuleGroups
	err := yaml.Unmarshal(s, &c)
	if err != nil {
		return nil, err
	}
	return c.Groups, nil
}
