package cli

import (
	"bytes"

	"github.com/yuin/goldmark/ast"
	"github.com/yuin/goldmark/parser"
	"github.com/yuin/goldmark/text"
)

var kindMath = ast.NewNodeKind("Math")

type mathNode struct {
	ast.BaseInline
	value   string // Unicode rendering for terminal display
	source  string // original LaTeX source (e.g. "\alpha", "\frac{1}{2}")
	display bool
}

func (n *mathNode) Kind() ast.NodeKind         { return kindMath }
func (n *mathNode) Dump(src []byte, level int) { ast.DumpHelper(n, src, level, nil, nil) }

type mathParser struct{}

func (p *mathParser) Trigger() []byte { return []byte{'$'} }

func (p *mathParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
	line, _ := block.PeekLine()
	if len(line) == 0 || line[0] != '$' {
		return nil
	}
	display := len(line) >= 2 && line[1] == '$'
	delim := 1
	if display {
		delim = 2
	}

	rest := line[delim:]
	var closeAt int
	if display {
		closeAt = bytes.Index(rest, []byte("$$"))
	} else {
		closeAt = bytes.IndexByte(rest, '$')
	}
	if closeAt < 0 {
		return nil
	}
	inner := rest[:closeAt]
	if len(bytes.TrimSpace(inner)) == 0 {
		return nil
	}

	// Currency guard (markdown-it-texmath rule): a single-$ span only counts as
	// math when the open isn't followed by space, the close isn't preceded by
	// space, and the char after the close isn't a digit — so "$5 and $10" stays
	// prose. Display $$ is unambiguous and skips the check.
	if !display {
		after := closeAt + 1
		if inner[0] == ' ' || inner[len(inner)-1] == ' ' ||
			(after < len(rest) && rest[after] >= '0' && rest[after] <= '9') {
			return nil
		}
	}

	block.Advance(delim + closeAt + delim)
	src := string(bytes.TrimSpace(inner))
	return &mathNode{value: latexToUnicode(src), source: src, display: display}
}
