// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package web

import (
	"bytes"
	"fmt"
	"html/template"
	"io/fs"
	"net/http"
	"net/url"
	"path"
	"regexp"
	"strings"
	"unicode/utf8"

	"github.com/yuin/goldmark"
	"github.com/yuin/goldmark/ast"
	"github.com/yuin/goldmark/extension"
	"github.com/yuin/goldmark/parser"
	"github.com/yuin/goldmark/renderer/html"
	"github.com/yuin/goldmark/text"
	"github.com/yuin/goldmark/util"
	"golang.org/x/website/internal/tmplfunc"
)

// RenderContent returns the HTML rendering for the page using the named base template
// (the standard base template is "site.tmpl").
func (site *Site) RenderContent(p Page, tmpl string) (template.HTML, error) {
	html, err := site.renderHTML(p, tmpl, &http.Request{URL: &url.URL{Path: "/missingurl"}})
	if err != nil {
		return "", err
	}
	return template.HTML(html), nil
}

// renderHTML renders and returns the Content and framed HTML for the page.
func (site *Site) renderHTML(p Page, tmpl string, r *http.Request) ([]byte, error) {
	// Clone p, because we are going to set its Content key-value pair.
	p2 := make(Page)
	for k, v := range p {
		p2[k] = v
	}
	p = p2

	url, ok := p["URL"].(string)
	if !ok {
		// Set URL - caller did not.
		p["URL"] = r.URL.Path
	}
	file, _ := p["File"].(string)
	data, _ := p["FileData"].(string)

	// Load base template.
	base, err := site.readFile(".", tmpl)
	if err != nil {
		return nil, err
	}

	dir := strings.Trim(path.Dir(url), "/")
	if dir == "" {
		dir = "."
	}
	sd := &siteDir{site, dir}

	t := template.New("site.tmpl").Funcs(template.FuncMap{
		"add":          func(a, b int) int { return a + b },
		"sub":          func(a, b int) int { return a - b },
		"mul":          func(a, b int) int { return a * b },
		"div":          func(a, b int) int { return a / b },
		"code":         sd.code,
		"data":         sd.data,
		"page":         sd.page,
		"pages":        sd.pages,
		"play":         sd.play,
		"request":      func() *http.Request { return r },
		"path":         func() pkgPath { return pkgPath{} },
		"strings":      func() pkgStrings { return pkgStrings{} },
		"file":         sd.file,
		"first":        first,
		"markdown":     markdown,
		"raw":          raw,
		"yaml":         yamlFn,
		"presentStyle": presentStyle,
	})
	t.Funcs(site.funcs)

	if err := tmplfunc.Parse(t, string(base)); err != nil {
		return nil, err
	}

	// Load page-specific layout template.
	layout, _ := p["layout"].(string)
	if layout == "" {
		l, ok := site.findLayout(dir, "default")
		if ok {
			layout = l
		} else {
			layout = "none"
		}
	} else if path.IsAbs(layout) {
		layout = strings.TrimLeft(path.Clean(layout+".tmpl"), "/")
	} else if strings.Contains(layout, "/") {
		layout = path.Join(dir, layout+".tmpl")
	} else if layout != "none" {
		l, ok := site.findLayout(dir, layout)
		if !ok {
			return nil, fmt.Errorf("cannot find layout %q", layout)
		}
		layout = l
	}

	if layout != "none" {
		ldata, err := site.readFile(".", layout)
		if err != nil {
			return nil, err
		}
		if err := tmplfunc.Parse(t.New(layout), string(ldata)); err != nil {
			return nil, err
		}
	}

	var buf bytes.Buffer
	if _, ok := p["Content"]; !ok && data != "" {
		// Either the page explicitly requested templating, or it is markdown,
		// which is treated as a template by default.
		isTemplate, explicit := p["template"].(bool)

		// Neither gopls nor the wiki are templated by default.
		if !explicit && (strings.HasPrefix(file, "wiki/") || strings.HasPrefix(file, "gopls/")) {
			isTemplate, explicit = false, true
		}

		tdata := data
		if !explicit || isTemplate {
			// Load content as a template.
			tf := t.New(file)
			if err := tmplfunc.Parse(tf, data); err != nil {
				return nil, err
			}
			if err := tf.Execute(&buf, p); err != nil {
				return nil, err
			}
			tdata = buf.String()
			buf.Reset()
		}

		if strings.HasSuffix(file, ".md") {
			html, err := markdownToHTML(tdata)
			if err != nil {
				return nil, err
			}
			p["Content"] = html
		} else {
			p["Content"] = template.HTML(tdata)
		}
	}

	if err := t.Execute(&buf, p); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// findLayout searches the start directory and parent directories for a template with the given base name.
func (site *Site) findLayout(dir, name string) (string, bool) {
	name += ".tmpl"
	for {
		abs := path.Join(dir, name)
		if _, err := fs.Stat(site.fs, abs); err == nil {
			return abs, true
		}
		if dir == "." {
			return "", false
		}
		dir = path.Dir(dir)
	}
}

// markdownToHTML converts Markdown to HTML.
// The Markdown source may contain raw HTML,
// but Go templates have already been processed.
func markdownToHTML(markdown string) (template.HTML, error) {
	// parser.WithHeadingAttribute allows custom ids on headings.
	// html.WithUnsafe allows use of raw HTML, which we need for tables.
	md := goldmark.New(
		goldmark.WithParserOptions(
			parser.WithHeadingAttribute(),
			parser.WithAutoHeadingID(),
			parser.WithASTTransformers(util.Prioritized(mdTransformFunc(mdLink), 1)),
		),
		goldmark.WithRendererOptions(html.WithUnsafe()),
		goldmark.WithExtensions(
			extension.NewTypographer(),
			extension.NewLinkify(
				extension.WithLinkifyAllowedProtocols([][]byte{[]byte("http"), []byte("https")}),
				extension.WithLinkifyEmailRegexp(regexp.MustCompile(`[^\x00-\x{10FFFF}]`)), // impossible
			),
			extension.DefinitionList,
			extension.NewTable(),
		),
	)
	var buf bytes.Buffer
	buf.WriteString("<div class='markdown'>\n")
	if err := md.Convert(replaceTabs([]byte(markdown)), &buf); err != nil {
		return "", err
	}
	buf.WriteString("</div>\n")
	return template.HTML(buf.Bytes()), nil
}

// mdTransformFunc is a func implementing parser.ASTTransformer.
type mdTransformFunc func(*ast.Document, text.Reader, parser.Context)

func (f mdTransformFunc) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
	f(node, reader, pc)
}

// mdLink walks doc, adding rel=noreferrer target=_blank to non-relative links.
func mdLink(doc *ast.Document, _ text.Reader, _ parser.Context) {
	mdLinkWalk(doc)
}

func mdLinkWalk(n ast.Node) {
	switch n := n.(type) {
	case *ast.Link:
		dest := string(n.Destination)
		if strings.HasPrefix(dest, "https://") || strings.HasPrefix(dest, "http://") {
			n.SetAttributeString("rel", []byte("noreferrer"))
			n.SetAttributeString("target", []byte("_blank"))
		}
		return
	case *ast.AutoLink:
		// All autolinks are non-relative.
		n.SetAttributeString("rel", []byte("noreferrer"))
		n.SetAttributeString("target", []byte("_blank"))
		return
	}

	for child := n.FirstChild(); child != nil; child = child.NextSibling() {
		mdLinkWalk(child)
	}
}

// replaceTabs replaces all tabs in text with spaces up to a 4-space tab stop.
//
// In Markdown, tabs used for indentation are required to be interpreted as
// 4-space tab stops. See https://spec.commonmark.org/0.30/#tabs.
// Go also renders nicely and more compactly on the screen with 4-space
// tab stops, while browsers often use 8-space.
// And Goldmark crashes in some inputs that mix spaces and tabs.
// Fix the crashes and make the Go code consistently compact across browsers,
// all while staying Markdown-compatible, by expanding to 4-space tab stops.
//
// This function does not handle multi-codepoint Unicode sequences correctly.
func replaceTabs(text []byte) []byte {
	var buf bytes.Buffer
	col := 0
	for len(text) > 0 {
		r, size := utf8.DecodeRune(text)
		text = text[size:]

		switch r {
		case '\n':
			buf.WriteByte('\n')
			col = 0

		case '\t':
			buf.WriteByte(' ')
			col++
			for col%4 != 0 {
				buf.WriteByte(' ')
				col++
			}

		default:
			buf.WriteRune(r)
			col++
		}
	}
	return buf.Bytes()
}
