package internal

import (
	htemplate "html/template"
	"net/url"
	"text/template"

	"tildegit.org/tjp/sliderule/gemini/gemtext"
)

var Renderers = map[gemtext.LineType]string{
	gemtext.LineTypeText:     "textline",
	gemtext.LineTypeLink:     "linkline",
	gemtext.LineTypeHeading1: "heading1line",
	gemtext.LineTypeHeading2: "heading2line",
	gemtext.LineTypeHeading3: "heading3line",
	gemtext.LineTypeQuote:    "quoteline",
}

func AddAllTemplates(base *template.Template, additions *template.Template) (*template.Template, error) {
	if additions == nil {
		return base, nil
	}

	tmpl := base
	var err error
	for _, addition := range additions.Templates() {
		tmpl, err = tmpl.AddParseTree(addition.Name(), addition.Tree)
		if err != nil {
			return nil, err
		}
	}

	return tmpl, nil
}

func AddHTMLTemplates(base *htemplate.Template, additions *htemplate.Template) (*htemplate.Template, error) {
	if additions == nil {
		return base, nil
	}

	tmpl := base
	var err error
	for _, addition := range additions.Templates() {
		tmpl, err = tmpl.AddParseTree(addition.Name(), addition.Tree)
		if err != nil {
			return nil, err
		}
	}

	return tmpl, nil
}

func ValidateLinks(doc gemtext.Document) error {
	for _, line := range doc {
		if linkLine, ok := line.(gemtext.LinkLine); ok {
			_, err := url.Parse(linkLine.URL())
			if err != nil {
				return err
			}
		}
	}
	return nil
}

type RenderItem struct {
	Template string
	Object   any
}

func RenderItems(doc gemtext.Document) []RenderItem {
	out := make([]RenderItem, 0, len(doc))
	out = append(out, RenderItem{
		Template: "header",
		Object:   doc,
	})

	inUL := false
	ulStart := 0
	inPF := false
	pfStart := 0

	for i, line := range doc {
		switch line.Type() {
		case gemtext.LineTypeListItem:
			if !inUL {
				inUL = true
				ulStart = i
			}
		case gemtext.LineTypePreformatToggle:
			if inUL {
				inUL = false
				out = append(out, RenderItem{
					Template: "listitemlines",
					Object:   doc[ulStart:i],
				})
			}
			if !inPF {
				inPF = true
				pfStart = i
			} else {
				inPF = false
				out = append(out, RenderItem{
					Template: "preformattedtextlines",
					Object:   doc[pfStart+1 : i],
				})
			}
		case gemtext.LineTypePreformattedText:
		default:
			if inUL {
				inUL = false
				out = append(out, RenderItem{
					Template: "listitemlines",
					Object:   doc[ulStart:i],
				})
			}

			if linkLine, ok := line.(gemtext.LinkLine); ok {
				line = validatedLinkLine{linkLine}
			}

			out = append(out, RenderItem{
				Template: Renderers[line.Type()],
				Object:   line,
			})
		}
	}

	if inUL {
		out = append(out, RenderItem{
			Template: "listitemlines",
			Object:   doc[ulStart:],
		})
	}

	out = append(out, RenderItem{
		Template: "footer",
		Object:   doc,
	})

	return out
}

type validatedLinkLine struct {
	gemtext.LinkLine
}

func (vll validatedLinkLine) ValidatedURL() htemplate.URL {
	return htemplate.URL(vll.URL())
}