package main

import (
	"fmt"
	"os"
	"reflect"
	"sort"
	"strconv"
	"strings"

	"github.com/muesli/termenv"
)

// 颜色配置枚举
type ColorProfile int

const (
	Auto ColorProfile = iota
	Dark
	Light
	NoColor
)

// 打印选项结构
type PrintOptions struct {
	ShowTypes      bool         // 是否显示类型信息
	ColorProfile   ColorProfile // 颜色配置方案
	FloatPrecision int          // 浮点数精度（-1表示自动）
}

// 颜色缓存变量
var (
	colorType  string
	colorField string
	colorKey   string
	colorValue string
	resetColor string
)

// 初始化颜色配置
func initColors(profile ColorProfile) {
	output := termenv.NewOutput(os.Stdout)
	style := output.String()
	resetColor = style.Reset().String()

	switch profile {
	case Auto:
		if output.HasDarkBackground() {
			setDarkThemeColors(output)
		} else {
			setLightThemeColors(output)
		}
	case Dark:
		setDarkThemeColors(output)
	case Light:
		setLightThemeColors(output)
	case NoColor:
		colorType = ""
		colorField = ""
		colorKey = ""
		colorValue = ""
		resetColor = ""
	}
}

// 暗色主题配色
func setDarkThemeColors(output *termenv.Output) {
	colorType = output.String().Foreground(output.Color("#5FAFFF")).String()
	colorField = output.String().Foreground(output.Color("#AFF080")).String()
	colorKey = output.String().Foreground(output.Color("#FFD700")).String()
	colorValue = output.String().Foreground(output.Color("#E0E0E0")).String()
}

// 亮色主题配色
func setLightThemeColors(output *termenv.Output) {
	colorType = output.String().Foreground(output.Color("#005FAF")).String()
	colorField = output.String().Foreground(output.Color("#008000")).String()
	colorKey = output.String().Foreground(output.Color("#AF5F00")).String()
	colorValue = output.String().Foreground(output.Color("#404040")).String()
}

// 美观打印入口函数
func PrettyPrint(v interface{}, opts ...PrintOptions) string {
	// 设置默认选项
	option := PrintOptions{
		ShowTypes:      true,
		ColorProfile:   Auto,
		FloatPrecision: -1,
	}
	if len(opts) > 0 {
		option = opts[0]
	}

	// 初始化颜色
	initColors(option.ColorProfile)

	// 开始递归打印
	return prettyPrint(reflect.ValueOf(v), 0, make(map[uintptr]bool), option, []bool{}).String()
}

// 行集合类型
type lines []string

func (l lines) String() string {
	return strings.Join(l, "\n")
}

// 核心打印逻辑
func prettyPrint(v reflect.Value, depth int, visited map[uintptr]bool, opts PrintOptions, lastMarkers []bool) lines {
	original := v
	// 处理指针和接口
	for {
		switch v.Kind() {
		case reflect.Ptr:
			if v.IsNil() {
				return lines{colorValue + "nil" + resetColor}
			}
			ptr := v.Pointer()
			if visited[ptr] {
				return lines{fmt.Sprintf("%s&%p%s", colorValue, v.Interface(), resetColor)}
			}
			visited[ptr] = true
			original = v
			v = v.Elem()
		case reflect.Interface:
			if v.IsNil() {
				return lines{colorValue + "nil" + resetColor}
			}
			v = v.Elem()
		default:
			goto END_DEREF
		}
	}
END_DEREF:

	var result lines
	prefix := buildPrefix(depth, lastMarkers)

	// 添加类型行
	if opts.ShowTypes && depth == 0 {
		typeLine := fmt.Sprintf("%s%s%s", colorType, getTypeName(original, v), resetColor)
		result = append(result, typeLine)
	}

	switch v.Kind() {
	case reflect.Struct:
		result = append(result, printStruct(v, depth, visited, opts, lastMarkers)...)
	case reflect.Map:
		result = append(result, printMap(v, depth, visited, opts, lastMarkers)...)
	case reflect.Slice, reflect.Array:
		result = append(result, printSlice(v, depth, visited, opts, lastMarkers)...)
	default:
		result = append(result, formatValue(v, prefix, opts))
	}

	return result
}

// 构建前缀字符串
func buildPrefix(depth int, lastMarkers []bool) string {
	if depth == 0 {
		return ""
	}

	var prefix strings.Builder
	for i := 0; i < depth-1; i++ {
		if i < len(lastMarkers) && lastMarkers[i] {
			prefix.WriteString("    ")
		} else {
			prefix.WriteString("│   ")
		}
	}

	if depth > 0 {
		if len(lastMarkers) > 0 && lastMarkers[len(lastMarkers)-1] {
			prefix.WriteString("└── ")
		} else {
			prefix.WriteString("├── ")
		}
	}
	return prefix.String()
}

// 获取类型名称
func getTypeName(original, v reflect.Value) string {
	if original.Kind() == reflect.Ptr {
		return original.Type().String()
	}
	return v.Type().String()
}

// 格式化值
func formatValue(v reflect.Value, prefix string, opts PrintOptions) string {
	switch v.Kind() {
	case reflect.String:
		return fmt.Sprintf("%s%s%q%s", prefix, colorValue, v.String(), resetColor)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return fmt.Sprintf("%s%s%d%s", prefix, colorValue, v.Int(), resetColor)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return fmt.Sprintf("%s%s%d%s", prefix, colorValue, v.Uint(), resetColor)
	case reflect.Float32, reflect.Float64:
		return formatFloat(v.Float(), opts.FloatPrecision, prefix)
	case reflect.Bool:
		return fmt.Sprintf("%s%s%t%s", prefix, colorValue, v.Bool(), resetColor)
	default:
		return fmt.Sprintf("%s%s%v%s", prefix, colorValue, v.Interface(), resetColor)
	}
}

// 格式化浮点数（改进精度处理）
func formatFloat(f float64, precision int, prefix string) string {
	var str string
	if precision >= 0 {
		str = strconv.FormatFloat(f, 'f', precision, 64)
	} else {
		// 自动处理精度
		str = strconv.FormatFloat(f, 'f', -1, 64)
		if strings.Contains(str, ".") {
			str = strings.TrimRight(str, "0")
			str = strings.TrimRight(str, ".")
		}
	}
	return fmt.Sprintf("%s%s%s%s", prefix, colorValue, str, resetColor)
}

// 打印结构体
func printStruct(v reflect.Value, depth int, visited map[uintptr]bool, opts PrintOptions, lastMarkers []bool) lines {
	var result lines
	fieldCount := v.NumField()

	for i := 0; i < fieldCount; i++ {
		field := v.Type().Field(i)
		fieldValue := v.Field(i)
		isLast := i == fieldCount-1

		newMarkers := append(lastMarkers, isLast)
		subLines := prettyPrint(fieldValue, depth+1, visited, opts, newMarkers)

		// 字段头
		fieldHeader := fmt.Sprintf("%s%s%s:",
			buildPrefix(depth+1, newMarkers[:len(newMarkers)-1]),
			colorField,
			field.Name,
		)

		if len(subLines) == 0 {
			result = append(result, fieldHeader+colorValue+"<invalid>"+resetColor)
			continue
		}

		// 合并字段头和数据
		result = append(result, fieldHeader+strings.TrimPrefix(subLines[0], buildPrefix(depth+1, newMarkers)))
		result = append(result, subLines[1:]...)
	}
	return result
}

// 打印Map
func printMap(v reflect.Value, depth int, visited map[uintptr]bool, opts PrintOptions, lastMarkers []bool) lines {
	var result lines
	keys := v.MapKeys()
	sort.Slice(keys, func(i, j int) bool {
		return fmt.Sprintf("%v", keys[i]) < fmt.Sprintf("%v", keys[j])
	})

	for i, key := range keys {
		isLast := i == len(keys)-1
		newMarkers := append(lastMarkers, isLast)

		keyLines := prettyPrint(key, depth+1, visited, opts, newMarkers)
		valueLines := prettyPrint(v.MapIndex(key), depth+1, visited, opts, newMarkers)

		// Key头
		keyHeader := fmt.Sprintf("%s%s%s:",
			buildPrefix(depth+1, newMarkers[:len(newMarkers)-1]),
			colorKey,
			strings.Join(keyLines, ""),
		)

		// 合并Key和Value
		if len(valueLines) > 0 {
			result = append(result, keyHeader+strings.TrimPrefix(valueLines[0], buildPrefix(depth+1, newMarkers)))
			result = append(result, valueLines[1:]...)
		} else {
			result = append(result, keyHeader+"<invalid>")
		}
	}
	return result
}

// 打印Slice/Array
func printSlice(v reflect.Value, depth int, visited map[uintptr]bool, opts PrintOptions, lastMarkers []bool) lines {
	var result lines
	for i := 0; i < v.Len(); i++ {
		isLast := i == v.Len()-1
		newMarkers := append(lastMarkers, isLast)
		elemLines := prettyPrint(v.Index(i), depth+1, visited, opts, newMarkers)
		result = append(result, elemLines...)
	}
	return result
}

// 测试结构体
type Person struct {
	Name    string
	Age     int
	Hobbies []string
	Address struct {
		City  string
		State string
	}
	Metadata map[string]interface{}
}

func main() {
	p := Person{
		Name:    "Alice",
		Age:     30,
		Hobbies: []string{"Reading", "Hiking"},
		Metadata: map[string]interface{}{
			"id":     123,
			"scores": []float64{98.5, 87.2000, 100.0},
			"nested": map[string]interface{}{"a": 1, "b": 2},
		},
	}
	p.Address.City = "New York"
	p.Address.State = "NY"
	p.Metadata["self_ref"] = &p

	fmt.Println("=== 默认输出（自动颜色适配）===")
	fmt.Println(PrettyPrint(p))

	fmt.Println("\n=== 显示类型+亮色主题+浮点精度2位 ===")
	fmt.Println(PrettyPrint(p, PrintOptions{
		ShowTypes:      true,
		ColorProfile:   Light,
		FloatPrecision: 2,
	}))

	fmt.Println("\n=== 不显示类型+暗色主题 ===")
	fmt.Println(PrettyPrint(p, PrintOptions{
		ShowTypes:    false,
		ColorProfile: Dark,
	}))
}
