// Copyright (C) 2019 Marius Schellenberger

package render

import (
	"git.giftfish.de/ston1th/gowiki/pkg/core"
	"github.com/blevesearch/bleve/analysis"
	"github.com/blevesearch/bleve/analysis/char/html"
	"github.com/russross/blackfriday"
	"html/template"
	"regexp"
	"strconv"
	"strings"
)

const delim = "+"

var filter = makeFilter()

func makeFilter() analysis.CharFilter {
	f, _ := html.CharFilterConstructor(nil, nil)
	return f
}

var (
	reHeader   = regexp.MustCompile("(<h[1-6]>)(.+)(</h[1-6]>)")
	reLink     = regexp.MustCompile(`id="(.+?)"`)
	whiteSpace = regexp.MustCompile(`\s+`)
	reIndex    = regexp.MustCompile("<h([1-6])>(.+)</h[1-6]>")
	titleRe    = regexp.MustCompile("[^a-zA-Z0-9 -]+")
)

func Render(p *core.Page) string {
	rend := blackfriday.MarkdownCommon([]byte(p.Markdown))
	toc, html := buildTOC(string(rend))
	html = strings.ReplaceAll(html, "<table>", `<table class="table">`)
	html = strings.ReplaceAll(html, "</h1>", `</h1><hr>`)
	html = strings.ReplaceAll(html, "<a", `<a target="_blank" rel="noopener noreferrer"`)
	html = strings.ReplaceAll(html, "\n</code", "</code")
	p.TOC = template.HTML(toc)
	p.HTML = template.HTML(html)
	return whiteSpace.ReplaceAllString(string(filter.Filter(rend)), " ")
}

func Title(title string) string {
	return whiteSpace.ReplaceAllString(titleRe.ReplaceAllString(title, ""), delim)
}

func Untitle(title string) string {
	return strings.ReplaceAll(title, delim, " ")
}

func StoreTitle(section, title string) string {
	return section + "/" + title
}

func SplitStoreTitle(st string) (section, title string) {
	a := strings.Split(st, "/")
	switch len(a) {
	case 1:
		return a[0], ""
	case 2:
		return a[0], a[1]
	}
	return
}

func buildTOC(html string) (string, string) {
	var toc string
	m := make(map[string]int)
	hn := reIndex.FindAllStringSubmatch(html, -1)
	html = reHeader.ReplaceAllString(html, `<a id="${2}" class="anchor"></a>${1}${2}${3}`)
	html = reLink.ReplaceAllStringFunc(html, func(s string) string {
		if len(s) >= 3 {
			return `id="` + Title(s[2:]) + `"`
		}
		return s
	})
	for k, v := range hn {
		link := Title(v[2])
		i := m[link]
		m[link] = i + 1
		newLink := link + strconv.Itoa(i)
		html = strings.Replace(html, link+`"`, newLink+`"`, 1)
		toc += before(hn, k)
		toc += `<li><a href="#` + newLink + `">` + v[2] + "</a>"
		toc += after(hn, k)
	}
	return toc, html
}

func before(arr [][]string, i int) string {
	c, _ := strconv.Atoi(arr[i][1])
	if c == 1 {
		return `<ul class="toc">`
	}
	return ""
}

func after(arr [][]string, i int) string {
	c, _ := strconv.Atoi(arr[i][1])
	if len(arr) <= i+1 {
		return closeTag(c-1) + "</ul>"
	}
	n, _ := strconv.Atoi(arr[i+1][1])
	switch {
	case n == 1:
		return closeTag(c-n) + "</ul>"
	case n < c:
		return closeTag(c - n)
	case n > c:
		return openTag(n - c)
	case n == c:
		return "</li>"
	}
	return ""
}

func openTag(j int) (ret string) {
	for i := 0; i < j; i++ {
		ret += `<ul class="toc"><li>`
	}
	ret = ret[0 : len(ret)-4]
	return
}

func closeTag(j int) (ret string) {
	for i := 0; i < j; i++ {
		ret += "</li></ul></li>"
	}
	if j > 1 {
		ret = strings.ReplaceAll(ret, "</li></li>", "</li>")
	}
	return
}
