package transform

import (
	"bytes"
	"errors"
	"fmt"
	"html/template"
	"reflect"

	"github.com/yuin/goldmark"
	"github.com/yuin/goldmark-emoji"
	"github.com/yuin/goldmark/extension"
	"github.com/yuin/goldmark/parser"
	renderer "github.com/yuin/goldmark/renderer/html"
)

type Namespace struct {
	markdown goldmark.Markdown
}

var ErrMarkdownify error = errors.New("unsupported input type for Markdownify")

func New() *Namespace {
	md := goldmark.New(
		// goldmark.WithParser(),
		// goldmark.WithRenderer(),
		goldmark.WithParserOptions(
			parser.WithAutoHeadingID(),
			parser.WithAttribute(),
		),
		goldmark.WithRendererOptions(
			renderer.WithUnsafe(),
		),
		goldmark.WithExtensions(
			extension.Table,
			extension.Strikethrough,
			extension.Linkify,
			extension.TaskList,
			extension.DefinitionList,
			extension.Footnote,
			extension.NewTypographer(
				extension.WithTypographicSubstitutions(extension.TypographicSubstitutions{
					extension.LeftDoubleQuote:  []byte(`„`),
					extension.LeftAngleQuote:   []byte(`«`),
					extension.RightDoubleQuote: []byte(`“`),
					extension.RightAngleQuote:  []byte(`»`),
				}),
			),
			emoji.Emoji,
		),
	)

	return &Namespace{
		markdown: md,
	}
}

func (ns *Namespace) Markdownify(v reflect.Value) (template.HTML, error) {
	var err error

	buf := bytes.NewBuffer(nil)

	switch v.Kind() {
	default:
		return "", ErrMarkdownify
	case reflect.Slice:
		switch v.Type().Elem().Kind() {
		default:
			return "", ErrMarkdownify
		case reflect.Uint8:
			err = ns.markdown.Convert(v.Bytes(), buf)
		}
	case reflect.String:
		err = ns.markdown.Convert(v.Bytes(), buf)
	}

	if err != nil {
		return "", fmt.Errorf("cannot convert input into markdown: %w", err)
	}

	return template.HTML(buf.String()), nil
}
