package languages

import (
	"strings"

	"github.com/zzet/gortex/internal/parser"
	sitter "github.com/zzet/gortex/internal/parser/tsitter"
)

// emitScalaAnnotationEdges scans the direct children of a class /
// object / trait / function / var-definition for `annotation` nodes
// and emits one EdgeAnnotated per annotation onto the synthetic
// `annotation::scala::<name>` node. Examples:
//
//	@deprecated("use newF", "1.5")  → annotation::scala::deprecated
//	@inline                          → annotation::scala::inline
//	@volatile                        → annotation::scala::volatile
//	@tailrec                         → annotation::scala::tailrec
//	@main                            → annotation::scala::main
//
// The Scala tree-sitter grammar places annotations as direct children
// of the annotated definition node, so we only scan the immediate
// child set — recursive walks would attribute method annotations to
// the enclosing class, which is wrong.
//
// `seen` deduplicates synthetic annotation nodes within the extraction
// pass; the graph layer also dedupes by ID so a miss here is wasted
// work, not a correctness bug.
func emitScalaAnnotationEdges(
	defNode *sitter.Node, fromID, filePath string, src []byte,
	result *parser.ExtractionResult, seen map[string]bool,
) {
	if defNode == nil || fromID == "" {
		return
	}
	for i := 0; i < int(defNode.NamedChildCount()); i++ {
		c := defNode.NamedChild(i)
		if c == nil || c.Type() != "annotation" {
			continue
		}
		name, args := scalaAnnotationNameAndArgs(c, src)
		if name == "" {
			continue
		}
		line := int(c.StartPoint().Row) + 1
		EmitAnnotationEdge(fromID, "scala", name, args, filePath, line, result, seen)
	}
}

// scalaAnnotationNameAndArgs reads an `annotation` node and returns
// (name, args). Name comes from the `type_identifier` child; args is
// the raw inner-parentheses text of an `arguments` child (or "" when
// the annotation has no argument list). Both return values are
// trimmed of surrounding whitespace.
//
// Multi-segment names like `@a.b.C` (qualified annotation references)
// are returned as the trailing segment ("C") so `find_usages` on the
// synthetic annotation node still groups every site that uses the
// same logical annotation regardless of import alias.
func scalaAnnotationNameAndArgs(annot *sitter.Node, src []byte) (string, string) {
	if annot == nil {
		return "", ""
	}
	var name, args string
	for i := 0; i < int(annot.NamedChildCount()); i++ {
		c := annot.NamedChild(i)
		if c == nil {
			continue
		}
		switch c.Type() {
		case "type_identifier", "identifier":
			if name == "" {
				name = strings.TrimSpace(c.Content(src))
			}
		case "stable_type_identifier", "projected_type":
			// Qualified annotation reference like `@scala.deprecated` —
			// keep only the trailing leaf so the synthetic node
			// matches every alias.
			text := strings.TrimSpace(c.Content(src))
			if idx := strings.LastIndex(text, "."); idx >= 0 {
				text = text[idx+1:]
			}
			if name == "" {
				name = text
			}
		case "arguments":
			text := strings.TrimSpace(c.Content(src))
			if len(text) >= 2 && text[0] == '(' && text[len(text)-1] == ')' {
				text = text[1 : len(text)-1]
			}
			args = strings.TrimSpace(text)
		}
	}
	return name, args
}
