package definitions

import (
	"github.com/Xuanwo/gg"
	"github.com/Xuanwo/templateutils"
	log "github.com/sirupsen/logrus"
)

type genNamespace struct {
	g *gg.Generator
}

func GenerateNamespace(path string) {
	gf := &genNamespace{
		g: gg.New(),
	}

	f := gf.g.NewGroup()
	f.AddLineComment("Code generated by go generate cmd/definitions; DO NOT EDIT.")
	f.AddPackage("definitions")
	f.NewImport().
		AddPath("fmt").
		AddLine().
		AddPath("github.com/beyondstorage/go-storage/v5/types")

	gf.generateNamespace(NamespaceService, OperationsService)
	gf.generateNamespace(NamespaceStorage, OperationsStorage)

	err := gf.g.WriteFile(path)
	if err != nil {
		log.Fatalf("generate to %s: %v", path, err)
	}
}

func (gf *genNamespace) generateNamespace(nsName string, ops []Operation) {
	f := gf.g.NewGroup()

	nsNameP := templateutils.ToPascal(nsName)

	structName := nsNameP
	sf := f.NewStruct(structName)
	sf.AddLine()
	sf.AddField("Features", "types."+nsNameP+"Features")
	sf.AddLine()
	for _, op := range ops {
		sf.AddField(templateutils.ToPascal(op.Name), "[]Pair")
	}

	f.NewFunction("ListPairs").
		WithReceiver("s", structName).
		AddParameter("name", "string").
		AddResult("", "[]Pair").
		AddBody(gg.Embed(func() gg.Node {
			g := gg.NewGroup()

			s := g.NewSwitch("name")
			for _, op := range ops {
				s.NewCase(gg.Lit(op.Name)).
					AddBody(gg.Return(
						gg.S("SortPairs(s.%s)", templateutils.ToPascal(op.Name))))
			}
			s.NewDefault().AddBody(`panic(fmt.Errorf("invalid op: %s", name))`)

			return g
		}))
}
