package utils

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/fatih/color"
	"github.com/hokaccha/go-prettyjson"
)

//***************************************************************************************************
// json (start)
//***************************************************************************************************
func MustToJson(data interface{}) string {
	s, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		panic(err)
	}
	return string(s)
}

// var defaultFormatter *colorjson.Formatter

func MustToJson_Color(data interface{}) string {
	// if defaultFormatter == nil {
	// 	defaultFormatter = colorjson.NewFormatter()
	// 	defaultFormatter.Indent = 2
	// }

	// s, err := defaultFormatter.Marshal(data)
	s, err := prettyjson.Marshal(data)
	if err != nil {
		panic(err)
	}
	return string(s)
}

func ToJson(data interface{}) (string, error) {
	jsBytes, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return "", err
	}
	return string(jsBytes), nil
}

func PrintJson(data interface{}) {
	fmt.Println(MustToJson(data))
}
func PrintJson_Color(data interface{}) {
	fmt.Println(MustToJson_Color(data))
}
//***************************************************************************************************
// json (end)
//***************************************************************************************************


//***************************************************************************************************
// common (start)
//***************************************************************************************************
func Highlight(s string, a ...any) {
	p := "----------------------------------------------------------------------------------------------------------------------------------------------------\n"
	fmt.Printf("%s%s%s\n%s%s", p, p, fmt.Sprintf(s, a...), p, p)
}

// if length == 0, set length = 140
func PrintTitle(title string, w byte, length int) string {
	const maxLen = 140
	if len(title) >= maxLen-2 {
		return title + "\n"
	}
	if length <= 0 || length > maxLen {
		length = maxLen
	}
	s := make([]byte, length+1)
	for i := range s {
		s[i] = w
	}
	s[length] = '\n'
	m := " " + title + " "
	copy(s[(length-len(m))/2:], []byte(m))
	return string(s)
}

func PrintLinesBeginWith(str string, prefix string) string {
	sp := strings.Split(str, "\n")
	for i, s := range sp {
		if len(sp[i]) > 0 {
			sp[i] = prefix + s
		}
	}
	return strings.Join(sp, "\n")
}

func padding(s string, length int, alignAtRight bool) string {
	if len(s) >= length {
		return s
	}
	padNum := length - len(s)
	ss := make([]byte, padNum)
	for i := 0; i < padNum; i++ {
		ss[i] = ' '
	}
	if alignAtRight {
		return string(ss) + s
	} else {
		return s + string(ss)
	}
}

func PrintAlignLines(lines []string, sep string, alignAtRight bool) []string {
	if len(lines) == 0 { return nil }
	var lineSeg [][]string
	var maxSegNum int
	for _, line := range lines {
		sp := strings.Split(line, sep)
		lineSeg = append(lineSeg, sp)
		if len(sp) > maxSegNum {
			maxSegNum = len(sp)
		}
	}

	maxWidth := make([]int, maxSegNum)
	for _, segs := range lineSeg {
		for i, seg := range segs {
			ln := len(seg)
			if maxWidth[i] < ln {
				maxWidth[i] = ln
			}
		}
	}
	
	var s []string
	for _, sp := range lineSeg {
		spLen := len(sp)
		if spLen == 0 { continue }
		if spLen == 1 {
			s = append(s, sp[0])
		} else {
			newSegs := make([]string, spLen)
			for i, s := range sp {
				if i == spLen - 1 {
					newSegs[i] = s
				} else {
					newSegs[i] = padding(s, maxWidth[i], alignAtRight)
				}
			}
			s = append(s, strings.Join(newSegs, sep))
		}
	}
	return s
}

func PrintAlignLine(lines []string, sep string) string {
	return strings.Join(PrintAlignLines(lines, sep, false), "")
}

func PrintAlignLine2(s string, sep string) string {
	return strings.Join(PrintAlignLines(strings.Split(s, "\n"), sep, false), "\n")
}

func PrintIndentLines(lines []string, indent int) string {
	prefix := make([]byte, indent)
	for i := range prefix {
		prefix[i] = ' '
	}
	str := ""
	for _, line := range lines {
		line := strings.TrimLeft(line, " ")
		str += string(prefix) + line
	}
	return str
}
func PrintIndent(s string, indent int) string {
	prefix := make([]byte, indent)
	for i := range prefix {
		prefix[i] = ' '
	}
	lines := strings.Split(s, "\n")
	for i, line := range lines {
		ss := strings.TrimLeft(line, " ")
		if len(ss) > 0 {
			lines[i] = string(prefix) + ss
		} else {
			lines[i] = line
		}
	}
	return strings.Join(lines, "\n")
}

func ColorBig(gtZero bool, format string, a ...interface{}) string {
	if gtZero {
		return color.RedString(format, a...)
	} else {
		return color.YellowString(format, a...)
	}
}

func AppendStr(strTo string, strNext string, sep string) string {
	if len(strTo) == 0 {
		return strNext
	} else {
		return fmt.Sprintf("%s%s %s", strTo, sep, strNext)
	}
}
//***************************************************************************************************
// common (end)
//***************************************************************************************************
