// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/cilium/ebpf"
)

var path, kind, name, embed, out string
var embeds []string

func init() {
	flag.StringVar(&path, "path", "", "path to the eBPF collection")
	flag.StringVar(&out, "out", "", "output Go file for the generated config struct")
	flag.StringVar(&kind, "kind", "object", "kind of the eBPF collection (object or node)")
	flag.StringVar(&name, "name", "", "name of the generated Go struct")
	flag.StringVar(&embed, "embed", "", "comma-separated list of structs to embed")

	flag.Parse()

	if embed != "" {
		embeds = strings.Split(embed, ",")
	}

	validate()
}

func main() {
	spec, err := ebpf.LoadCollectionSpec(path)
	if err != nil {
		errexit(fmt.Errorf("loading spec: %w", err))
	}

	comment := fmt.Sprintf("%s is a configuration struct for a Cilium datapath object. "+
		"Warning: do not instantiate directly! Always use [New%s] to ensure the default "+
		"values configured in the ELF are honored.", name, name)
	s, err := varsToStruct(spec, name, kind, comment, embeds)
	if err != nil {
		errexit(fmt.Errorf("generating config struct: %w", err))
	}

	var b strings.Builder
	b.WriteString("// Code generated by dpgen. DO NOT EDIT.\n")
	b.WriteString("\n")
	b.WriteString("// SPDX-License-Identifier: Apache-2.0\n")
	b.WriteString("// Copyright Authors of Cilium\n")
	b.WriteString("\n")
	b.WriteString("package config\n")
	b.WriteString("\n")
	b.WriteString(s)

	os.WriteFile(out, []byte(b.String()), 0644)
}

func validate() {
	if path == "" {
		exit("path cannot be empty")
	}

	if name == "" {
		exit("name cannot be empty")
	}

	if out == "" {
		exit("out cannot be empty")
	}

	if kind != "object" && kind != "node" {
		exit("kind needs to be 'object' or 'node'")
	}
}

func exit(s string) {
	fmt.Fprintln(os.Stderr, s)
	os.Exit(1)
}

func errexit(err error) {
	exit(err.Error())
}
