package markdown

import (
	"html"
	"strings"
)

// MarkdownToHTML converts a basic subset of markdown to HTML, for
// use in the news posts, forums, or user blurbs.
func MarkdownToHTML(s string) string {
	// Escape HTML entities first to sanitize user input
	s = html.EscapeString(s)

	// Handle headers first (line-based)
	lines := strings.Split(s, "\n")
	for i, line := range lines {
		line = strings.TrimSpace(line)
		if strings.HasPrefix(line, "### ") {
			lines[i] = "<h3>" + line[4:] + "</h3>"
		} else if strings.HasPrefix(line, "## ") {
			lines[i] = "<h2>" + line[3:] + "</h2>"
		} else if strings.HasPrefix(line, "# ") {
			lines[i] = "<h1>" + line[2:] + "</h1>"
		}
	}
	s = strings.Join(lines, "\n")

	// Handle code spans before other formatting
	s = replaceCodeSpans(s)

	// Handle links [text](url)
	s = replaceLinks(s)

	// Handle bold and italic
	s = replaceBoldItalic(s)

	// Handle line breaks last
	s = strings.ReplaceAll(s, "\n", "<br>")

	return `<div class="md-lib">` + s + "</div>"
}

func replaceCodeSpans(s string) string {
	for {
		start := strings.Index(s, "`")
		if start == -1 {
			break
		}
		end := strings.Index(s[start+1:], "`")
		if end == -1 {
			break
		}
		end += start + 1
		code := s[start+1 : end]
		s = s[:start] + "<code>" + code + "</code>" + s[end+1:]
	}
	return s
}

func replaceLinks(s string) string {
	for {
		linkStart := strings.Index(s, "[")
		if linkStart == -1 {
			break
		}
		linkEnd := strings.Index(s[linkStart:], "](")
		if linkEnd == -1 {
			break
		}
		linkEnd += linkStart
		urlStart := linkEnd + 2
		urlEnd := strings.Index(s[urlStart:], ")")
		if urlEnd == -1 {
			break
		}
		urlEnd += urlStart

		text := s[linkStart+1 : linkEnd]
		url := s[urlStart:urlEnd]
		s = s[:linkStart] + `<a href="` + url + `">` + text + "</a>" + s[urlEnd+1:]
	}
	return s
}

func replaceBoldItalic(s string) string {
	// Handle bold first
	for strings.Contains(s, "**") {
		first := strings.Index(s, "**")
		if first == -1 {
			break
		}
		second := strings.Index(s[first+2:], "**")
		if second == -1 {
			break
		}
		second += first + 2
		text := s[first+2 : second]
		s = s[:first] + "<b>" + text + "</b>" + s[second+2:]
	}

	// Handle italic
	for strings.Contains(s, "*") {
		first := strings.Index(s, "*")
		if first == -1 {
			break
		}
		second := strings.Index(s[first+1:], "*")
		if second == -1 {
			break
		}
		second += first + 1
		text := s[first+1 : second]
		s = s[:first] + "<i>" + text + "</i>" + s[second+1:]
	}

	return s
}
