package matrix

import (
	"fmt"
	"html"
	"net/url"
	"strings"
)

// safeHref returns raw if it is an http(s) URL, else "". Keeps feed-supplied
// links from injecting javascript:/data: schemes into the formatted_body href
// (html.EscapeString blocks attribute breakout but not the scheme itself).
func safeHref(raw string) string {
	u, err := url.Parse(strings.TrimSpace(raw))
	if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
		return ""
	}
	return raw
}

// PostableStory contains the data needed to format and send a story.
type PostableStory struct {
	ImageURL   string
	Headline   string
	ArticleURL string
	Lede       string
	Source     string
	Channel    string
	Platforms  []string
}

// formatPost returns plain text and HTML bodies for a Matrix message.
func formatPost(s *PostableStory) (plain, htmlBody string) {
	// Plain text body
	var plainParts []string
	plainParts = append(plainParts, fmt.Sprintf("**%s** \u2192 %s", s.Headline, s.ArticleURL))
	if s.Lede != "" {
		plainParts = append(plainParts, s.Lede)
	}
	if tag := formatSourceTag(s.Source, s.Platforms, false); tag != "" {
		plainParts = append(plainParts, tag)
	}
	plain = strings.Join(plainParts, "\n")

	// HTML body
	var htmlParts []string
	if href := safeHref(s.ArticleURL); href != "" {
		htmlParts = append(htmlParts, fmt.Sprintf(
			`<strong><a href="%s">%s</a></strong>`,
			html.EscapeString(href),
			html.EscapeString(s.Headline),
		))
	} else {
		// Non-http(s) link: render the headline without an anchor.
		htmlParts = append(htmlParts, fmt.Sprintf(`<strong>%s</strong>`, html.EscapeString(s.Headline)))
	}
	if s.Lede != "" {
		htmlParts = append(htmlParts, html.EscapeString(s.Lede))
	}
	if tag := formatSourceTag(s.Source, s.Platforms, true); tag != "" {
		htmlParts = append(htmlParts, tag)
	}
	htmlBody = strings.Join(htmlParts, "<br/>")

	return plain, htmlBody
}

// formatSourceTag builds the source + platform tags line. An empty source is
// omitted rather than tagged: Pete's own reporting has no outlet to credit, and
// an empty tag would read as him signing his own name.
func formatSourceTag(source string, platforms []string, isHTML bool) string {
	var parts []string
	if source != "" {
		parts = append(parts, strings.ToLower(source))
	}
	parts = append(parts, platforms...)
	if len(parts) == 0 {
		return ""
	}
	for i, p := range parts {
		if isHTML {
			parts[i] = fmt.Sprintf("<code>%s</code>", html.EscapeString(p))
		} else {
			parts[i] = fmt.Sprintf("`%s`", p)
		}
	}
	return strings.Join(parts, " \u00b7 ")
}
