package main

import (
	"fmt"
	"go/ast"
	"strings"

	"golang.org/x/tools/go/packages"
)

type Param struct {
	Key          string `json:"key"`
	Type         string `json:"type"`
	DefaultValue any    `json:"default_value,omitempty"`
	Comment      string `json:"comment,omitempty"`
}

// StructComments stores field comments keyed by "TypeName.FieldName"
type StructComments map[string]string

// LoadPackageComments loads a package and extracts all struct field comments
func LoadPackageComments(pkgPath string) (StructComments, error) {
	cfg := &packages.Config{
		Mode: packages.NeedSyntax | packages.NeedTypes | packages.NeedName,
	}
	pkgs, err := packages.Load(cfg, pkgPath)
	if err != nil {
		return nil, fmt.Errorf("failed to load package %s: %w", pkgPath, err)
	}
	if len(pkgs) == 0 {
		return nil, fmt.Errorf("no packages found for %s", pkgPath)
	}

	comments := make(StructComments)
	for _, pkg := range pkgs {
		for _, file := range pkg.Syntax {
			extractStructComments(file, comments)
		}
	}
	return comments, nil
}

func extractStructComments(file *ast.File, comments StructComments) {
	ast.Inspect(file, func(n ast.Node) bool {
		typeSpec, ok := n.(*ast.TypeSpec)
		if !ok {
			return true
		}
		structType, ok := typeSpec.Type.(*ast.StructType)
		if !ok {
			return true
		}
		typeName := typeSpec.Name.Name
		for _, field := range structType.Fields.List {
			var comment string
			if field.Doc != nil {
				comment = strings.TrimSpace(field.Doc.Text())
			} else if field.Comment != nil {
				comment = strings.TrimSpace(field.Comment.Text())
			}
			if comment == "" {
				continue
			}
			for _, name := range field.Names {
				key := typeName + "." + name.Name
				comments[key] = comment
			}
		}
		return true
	})
}

type UnmarshalText interface {
	UnmarshalText([]byte) error
}

type UnmarshalTOML interface {
	UnmarshalTOML(any) error
}
