package main

import (
	"bytes"
	"os"
	"path"
	"reflect"
	"strconv"
	"strings"
	"time"

	"gopkg.in/yaml.v3"

	"github.com/olekukonko/tablewriter"
)

type document struct {
	ToDos    []task `yaml:"-"`
	Absolute string `yaml:"-"`
	File     string `yaml:"-"`

	// remember the node structure of yaml
	OriginNode *yaml.Node `yaml:"-"`
	OriginText string     `yaml:"-"`

	Name       string    `yaml:"Name"`
	References []string  `yaml:"References"`
	Keywords   []string  `yaml:"Keywords"`
	Author     []string  `yaml:"Author"`
	Version    string    `yaml:"Version"`
	Created    time.Time `yaml:"Created"`
	LastUpdate time.Time `yaml:"Last Update"`
}

func addDocument() error {

	if arguments.Documents.Add.Name == "" {
		printErrorAndExit(2, "the name must not be empty")
	}

	p := path.Join(arguments.Path, arguments.Documents.Add.Name+".md")
	if fileExists(p) {
		printErrorAndExit(2, "the request with id already exists", arguments.Documents.Add.Name, p)
	}

	t := config.Requirement.Template.Add
	t = strings.Replace(t, "%%ID%%", arguments.Documents.Add.Name, -1)
	t = strings.Replace(t, "%%CREATED%%", time.Now().Format("2006-01-02"), -1)

	d1 := []byte(t)
	err := os.WriteFile(p, d1, 0644)
	if err != nil {
		return err
	}

	return nil
}

func buildRequirements(pageMap map[string]*document) (error, string, bool) {

	hasRequirements := false

	buf := new(bytes.Buffer)
	table := tablewriter.NewWriter(buf)

	translateMetaColumns := translateHeaders(config.Requirement.Table.Columns)

	table.SetHeader(translateMetaColumns)
	table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
	table.SetCenterSeparator("|")

	var tableData [][]string

	for _, pd := range pageMap {

		r := reflect.ValueOf(pd)

		var row []string
		found := false
		for _, name := range config.Requirement.Table.Columns {

			field := reflect.Indirect(r).FieldByName(name)
			if field == (reflect.Value{}) {
				row = append(row, printer.Sprintf("no value"))
				continue
			}

			t := field.Type()

			switch t.Name() {
			case "string":
				found = true
				row = append(row, field.String())
			case "Duration":
				found = true
				t := field.Interface().(time.Duration)
				row = append(row, t.String())
			case "Time":
				found = true
				t := field.Interface().(time.Time)
				if t.IsZero() {
					row = append(row, "—")
				} else {
					row = append(row, field.Interface().(time.Time).Format(config.Locale.DateFormat))
				}
			case "int":
				found = true
				row = append(row, strconv.FormatInt(field.Int(), 10))
			case "float64":
				found = true
				row = append(row, strconv.FormatFloat(field.Float(), 'f', 10, 2))
			case "nil":
				row = append(row, field.String())
			case "bool":
				found = true
				expr := field.Bool()
				if expr {
					row = append(row, "true")
				} else {
					row = append(row, "false")
				}

			default:
				row = append(row, printer.Sprintf("unsuported type", t.Name()))
			}

		}

		if found {
			tableData = append(tableData, row)
			hasRequirements = true
		}

	}

	table.AppendBulk(tableData) // Add Bulk Data
	table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
	table.Render()

	return nil, buf.String(), hasRequirements

}