package console

import (
	"bytes"
	"fmt"
	"strings"
	"time"
	"unicode/utf8"
)

type Table struct {
	Bordered bool
	Values   [][]interface{}
}

func (table *Table) AddRow(vs ...interface{}) {
	table.Values = append(table.Values, vs)
}

func (table *Table) WithBordered() *Table {
	table.Bordered = true
	return table
}

func printBorder(w *bytes.Buffer, ws []int) {
	for _, l := range ws {
		w.WriteString("+")
		w.WriteString(strings.Repeat("-", l+2))
	}
	w.WriteString("+\n")
}

func calcCharsetWidth(s string) int {
	bl := len(s)
	ul := utf8.RuneCountInString(s)
	if bl == ul {
		return bl
	} else {
		var wc int
		//计算中文词语数量，并且替换为2个长度显示
		for wc = ((bl - ul) / 3); wc < ul; wc++ {
			if wc*3-wc == bl-ul {
				break
			}
		}
		wv := wc*2 + (ul - wc)
		return wv
	}
}

func (table *Table) toString(v interface{}) string {
	switch t := v.(type) {
	case float32, float64:
		return fmt.Sprintf("%.2f", t)
	case time.Time:
		return t.Format("2006-01-02 15:04:05")
	default:
		return fmt.Sprint(v)
	}
}

func (table *Table) Marshal() ([]byte, error) {
	columns := make([][]string, 0)
	var widths []int
	var width int
	var maxLength int

	calcWidth := calcCharsetWidth
	for _, value := range table.Values {
		if len(value) > maxLength {
			maxLength = len(value)
		}
	}
	widths = make([]int, maxLength)
	for _, vs := range table.Values {
		vl := len(vs)
		column := make([]string, vl)
		for i, val := range vs {
			str := table.toString(val)
			if vl > 1 {
				width = calcWidth(str)
				if width > widths[i] {
					widths[i] = width
				}
			}
			column[i] = str
		}
		columns = append(columns, column)
	}
	buffer := &bytes.Buffer{}
	if table.Bordered {
		printBorder(buffer, widths)
	}
	for index, column := range columns {
		cl := len(column)
		for i, w := range widths {
			if table.Bordered {
				buffer.WriteString("|")
			}
			var str string
			if cl > i {
				str = column[i]
			}
			if table.Bordered {
				buffer.WriteString(" ")
			}
			buffer.WriteString(str)
			cl := calcWidth(str)
			if widths[i] >= cl {
				buffer.WriteString(strings.Repeat(" ", w-cl))
			}
			buffer.WriteString(" ")
			//key value options
			if len(widths) == 2 && i == 0 && len(column) == 2 && !table.Bordered {
				buffer.WriteString("\t")
			}
		}
		if table.Bordered {
			buffer.WriteString("|\n")
		} else {
			buffer.WriteString("\n")
		}
		if table.Bordered && index == 0 {
			printBorder(buffer, widths)
		}
	}
	if table.Bordered {
		printBorder(buffer, widths)
	}
	return buffer.Bytes(), nil
}

func NewTable() *Table {
	return &Table{
		Bordered: false,
		Values:   make([][]interface{}, 0),
	}
}
