package formatters

import (
	"fmt"
	"github.com/jedib0t/go-pretty/v6/table"
	"gitlab.com/pcanilho/go-jira"
	"gopkg.in/yaml.v2"
	"os"
	"sort"
)

type tableFormatter struct {
	writer table.Writer
	format string
}

var (
	issueFormatKeys = keys(issueToMap(jira.Issue{}))
	selectedFields  = []string{"id", "key"}
)

func NewTableFormatter(format string) *tableFormatter {
	sort.Strings(issueFormatKeys)
	tableWriter := table.NewWriter()

	var cs []interface{}
	for i := 0; i < len(issueFormatKeys); i++ {
		cs = append(cs, issueFormatKeys[i])
	}

	tableWriter.AppendHeader(cs)
	return &tableFormatter{
		writer: tableWriter,
		format: format,
	}
}

func (t *tableFormatter) Serialise(v interface{}) string {
	if v == nil {
		return ""
	}

	switch s := v.(type) {
	case []jira.Issue:
		t.serialiseIssues(s...)
	case jira.Issue:
		t.serialiseIssue(s)
	case *jira.Issue:
		t.serialiseIssue(*s)
	default:
		_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("table formatter: the type [%T] is not supported!", v))
		return ""
	}

	var renderFunc func() string
	switch t.format {
	case "markdown":
		renderFunc = t.writer.RenderMarkdown
	case "csv":
		renderFunc = t.writer.RenderCSV
	case "html":
		renderFunc = t.writer.RenderHTML
	default:
		renderFunc = t.writer.Render
	}
	return renderFunc()
}

func (t *tableFormatter) serialiseIssues(issues ...jira.Issue) {
	if issues == nil {
		return
	}
	for _, i := range issues {
		t.serialiseIssue(i)
		//if c <= len(issues)-2 {
		//	t.writer.AppendSeparator()
		//}
	}
}

func (t *tableFormatter) serialiseIssue(issue jira.Issue) {
	issueMap := issueToMap(issue)
	var vs []interface{}
	for _, k := range issueFormatKeys {
		vs = append(vs, issueMap[k])
	}
	t.writer.AppendRow(vs)
}

func issueToMap(issue jira.Issue) map[string]interface{} {
	b, _ := yaml.Marshal(issue)
	var kvs map[string]interface{}
	_ = yaml.Unmarshal(b, &kvs)
	return kvs
}

func keys(kvs map[string]interface{}) (out []string) {
	for k, _ := range kvs {
		var selected bool
		for _, i := range selectedFields {
			if i == k {
				selected = true
			}
		}
		if selected {
			out = append(out, k)
		}
	}
	return
}