//go:build ignore

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"log"
	"strings"

	"codeberg.org/miekg/dns/internal/generate"
)

var hdr = `
// Code generated by "go run dsolen_generate.go"; DO NOT EDIT.

package dns

`

const out = "zdsolen.go"

// we assume simple core Go types, not structs in these

func main() {
	flag.Parse()
	specs, err := generate.StructTypeSpecs("dso_types.go")
	if err != nil {
		log.Fatalf("Failed to generate %s: %v", out, err)
	}
	b := &bytes.Buffer{}
	b.WriteString(hdr)

	for _, spec := range specs {
		rrname := spec.Name.Name

		fmt.Fprintf(b, "func (rr *%s) Len() int {\n", rrname)
		fmt.Fprintf(b, "l := 0\n")

		strct := spec.Type.(*ast.StructType)
		for _, field := range strct.Fields.List {
			if len(field.Names) == 0 {
				continue
			}

			fieldname := field.Names[0].String()
			// fieldtype is singular type name.
			fieldtype := ""
			if id, ok := field.Type.(*ast.Ident); ok {
				fieldtype = id.Name
			}

			tag := ""
			if field.Tag != nil {
				tag = strings.Trim(field.Tag.Value, "`")
			}

			o := func(s string) { fmt.Fprintf(b, s, fieldname) }

			switch {
			case tag == `dns:"-"`:
				// ignored
			case tag == `dns:"hex"`:
				o("l += len(rr.%s)/2\n")
			case tag == `dns:"any"`:
				o("l += len(rr.%s)\n")
			case tag == "":
				switch fieldtype {
				case "uint8":
					o("l++ // %s\n")
				case "uint16":
					o("l += 2 // %s\n")
				case "uint32":
					o("l += 4 // %s\n")
				case "uint64":
					o("l += 8 // %s\n")
				case "string":
					o("l += len(rr.%s) + 1\n")
				default:
					log.Fatalf("No tag or basic type: %s: %q, %s", rrname, fieldname, tag)
				}
			default:
				log.Fatalf("No tag or basic type: %s: %q, %s", rrname, fieldname, tag)
			}
		}
		fmt.Fprint(b, "return l }\n\n")
	}

	generate.Write(b, out)
}
