package search

import (
	"strings"

	"github.com/antchfx/htmlquery"
	"github.com/vulncheck-oss/go-exploit/output"
)

// XPath returns a single HTML XPath match inner text, allowing the extraction of HTML nodes and
// attributes. This is useful in situations where you might reach for regular expressions, but want
// to have a bit more reliability if the HTML document is consistent. The function will return an
// empty string and false boolean if the HTML node cannot be found or the XPath query is invalid,
// the latter of which should only occur during development.
func XPath(document, path string) (string, bool) {
	doc, err := htmlquery.Parse(strings.NewReader(document))
	if err != nil {
		output.PrintfFrameworkError("Could not parse HTML document: %s", err.Error())

		return "", false
	}
	n := htmlquery.FindOne(doc, path)
	if n == nil {
		output.PrintfFrameworkError("Could not find HTML node")

		return "", false
	}

	return htmlquery.InnerText(n), true
}

// XPathAll returns all matched HTML XPath match inner text. This can be used in scenarios that it
// is necessary to extract multiple values from matching HTML documents.
func XPathAll(document, path string) ([]string, bool) {
	matches := []string{}
	doc, err := htmlquery.Parse(strings.NewReader(document))
	if err != nil {
		output.PrintfFrameworkError("Could not parse HTML document: %s", err.Error())

		return []string{}, false
	}
	n := htmlquery.Find(doc, path)
	if n == nil {
		output.PrintfFrameworkError("Could not find any HTML node")

		return []string{}, false
	}
	for _, d := range n {
		matches = append(matches, htmlquery.InnerText(d))
	}

	return matches, true
}
