// Package forms has helper functions for working with HTML forms.
package forms

import (
	"context"
	"io"
	"net/http"
	"net/url"
	"strings"

	"golang.org/x/net/html"
)

// A Form represents an HTML form.
type Form struct {
	Action string
	Method string
	Inputs map[string]string
}

// Parse parses all the forms in an HTML document.
func Parse(r io.Reader) []Form {
	root, err := html.Parse(r)
	if err != nil {
		return nil
	}

	var forms []Form
	var currentForm *Form
	var visit func(*html.Node)
	visit = func(node *html.Node) {
		if node.Type == html.ElementNode && node.Data == "form" {
			currentForm = &Form{Action: "", Method: "GET", Inputs: make(map[string]string)}
			for _, attr := range node.Attr {
				switch attr.Key {
				case "action":
					currentForm.Action = attr.Val
				case "method":
					currentForm.Method = strings.ToUpper(attr.Val)
				}
			}
		}

		if currentForm != nil && node.Type == html.ElementNode && node.Data == "input" {
			var name, value string
			for _, attr := range node.Attr {
				switch attr.Key {
				case "name":
					name = attr.Val
				case "value":
					value = attr.Val
				}
			}
			if name != "" {
				currentForm.Inputs[name] = value
			}
		}

		for c := node.FirstChild; c != nil; c = c.NextSibling {
			visit(c)
		}
		if node.Type == html.ElementNode && node.Data == "form" {
			if currentForm != nil {
				forms = append(forms, *currentForm)
			}
			currentForm = nil
		}
	}
	visit(root)
	return forms
}

// NewRequestWithContext creates a new request from the form details.
func (f *Form) NewRequestWithContext(ctx context.Context, baseURL *url.URL) (*http.Request, error) {
	actionURL, err := url.Parse(f.Action)
	if err != nil {
		return nil, err
	}
	actionURL = baseURL.ResolveReference(actionURL)

	vs := make(url.Values)
	for k, v := range f.Inputs {
		vs.Set(k, v)
	}

	req, err := http.NewRequestWithContext(ctx, f.Method, actionURL.String(), strings.NewReader(vs.Encode()))
	if err != nil {
		return nil, err
	}
	//TODO: handle multipart forms
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return req, nil
}