package utils

import (
	"fmt"
	"regexp"
	"slices"
	"strings"
	"sync/atomic"
	"testing"
	"time"

	"github.com/charmbracelet/lipgloss"
	"github.com/charmbracelet/lipgloss/tree"
	"github.com/emirpasic/gods/v2/maps/treemap"
	"github.com/shirou/gopsutil/v4/process"
)

func TestRegexp(t *testing.T) {
	t.Log(ReUnit.MatchString("b"))
	t.Log(ReUnit.MatchString("kb"))
	t.Log(ReUnit.MatchString("kib"))

	t.Logf("%+v, %d", ReUnit.FindStringSubmatch("b"), len(ReUnit.FindStringSubmatch("b")))
	t.Logf("%+v, %d", ReUnit.FindStringSubmatch("kb"), len(ReUnit.FindStringSubmatch("kb")))
	t.Logf("%+v, %d", ReUnit.FindStringSubmatch("kib"), len(ReUnit.FindStringSubmatch("kib")))

	if ReStorageSize.MatchString("123MiB") {
		t.Logf("%+v", ReStorageSize.FindStringSubmatch("123MiB"))
	} else {
		t.Errorf("Error match 123MiB")
	}

	if ReStorageSize.MatchString("123MB") {
		t.Logf("%+v", ReStorageSize.FindStringSubmatch("123MB"))
	} else {
		t.Errorf("Error match 123MB")
	}
}

func TestParseUnit(t *testing.T) {
	testData := []string{"MiB", "MB", "B", "b"}
	result := []StorageCapacityUnit{MiB, MB, Byte, Byte}
	for index, unit := range testData {
		u, err := ParseUnit(unit)
		if err != nil {
			t.Errorf("Error match %d: %s", index, err)
		}
		if u != result[index] {
			t.Errorf("Error match %d: expected %d, got %d", index, u, result[index])
		}
	}
}

func TestParseMemorySize(t *testing.T) {
	testData := []string{"1MiB", "2MB", "3B", "4b", "5 PiB"}
	result := []MemorySize{{Num: 1, Unit: MiB}, {Num: 2, Unit: MB}, {Num: 3, Unit: Byte}, {Num: 4, Unit: Byte}, {Num: 5, Unit: PiB}}
	for index, unit := range testData {
		u, err := ParseMemorySize(unit)
		if err != nil {
			t.Errorf("Error match %d: %s", index, err)
		}
		if u.Num != result[index].Num || u.Unit != result[index].Unit {
			t.Errorf("Error match %d: expected %d, got %d", index, u, result[index])
		}
	}
}

func TestHumanReadStr(t *testing.T) {
	ms := MemorySize{Num: 0, Unit: Byte}
	t.Log(ms.HumanReadStr(2))
	ms.Num = 1025
	ms.Unit = PiB
	t.Log(ms.HumanReadStr(1))
}

func TestPCIBusId(t *testing.T) {
	t.Log(PCIBus(0x1, 1))
	t.Log(PCIBus(0x12, 1))
	t.Log(PCIBus(0x123, 1))
	t.Log(PCIBus(0x1234, 1))
	t.Log(PCIBus(0x12345, 1))
	t.Log(PCIBus(0x123456, 1))
	t.Log(PCIBus(0x1234567, 1))
	t.Log(PCIBus(0x12345678, 1))
	t.Log(PCIBus(0x123456789, 1))
	i := atomic.Int32{}
	t.Log(i.Load())
}

func TestTimesort(t *testing.T) {
	fmt.Println("--- 打印所有 256 个 8 点盲文（Unicode 字符）---")
	fmt.Println("  (如果您的字体支持，将显示从 U+2800 到 U+28FF 的符号)")
	fmt.Println(strings.Repeat("-", 60))

	// 8点盲文的 Unicode 范围是 U+2800 到 U+28FF
	const startCodePoint = 0x2800
	const endCodePoint = 0x28FF
	const charsPerRow = 16 // 每行打印 16 个字符，共 16 行

	// 循环遍历并打印所有 256 个字符
	for i := startCodePoint; i <= endCodePoint; i++ {
		// 打印 Unicode 符号本身
		fmt.Printf("%c", rune(i))

		// 每 16 个字符换一行
		if (i-startCodePoint+1)%charsPerRow == 0 {
			fmt.Print("\n")
		} else {
			fmt.Print("|") // 字符之间用空格分隔
		}
	}

	fmt.Println(strings.Repeat("-", 60))
	fmt.Println("所有 256 个组合打印完成 (从 U+2800 到 U+28FF)。")
}

func TestChartype(t *testing.T) {
	r := GetCharType(LeftFullMW)
	t.Log(r)
	t.Log(CharTypeOr(GetCharType(' '), GetCharType(' ')))
	t.Log(GetCharType('⢠'))
	s := treemap.NewWith[time.Time, int](func(x, y time.Time) int {
		if x.Before(y) {
			return -1
		}
		if x.After(y) {
			return 1
		}
		return 0
	})

	s.Put(time.Now(), 3)
	s.Put(time.Now().Add(time.Second), 2)
	s.Put(time.Now().Add(-2*time.Second), 9)
	i := s.Iterator()
	for {
		if !i.Next() {
			break
		}
		t.Logf("%v: %d", i.Key(), i.Value())
	}
}

func ff(t *tree.Tree, root *ProcessInfo, ctx []int32) []int32 {
	ctx = append(ctx, root.Pid)
	pids := make([]int32, 0, len(root.Child))
	for k := range root.Child {
		pids = append(pids, k)
	}
	slices.Sort(pids)
	for _, v := range pids {
		c := root.Child[v]
		tt := tree.New().Root(fmt.Sprintf("%d: %s", c.Pid, c.Cmd))
		t.Child(tt)
		if len(c.Child) > 0 {
			ctx = ff(tt, c, ctx)
		} else {
			ctx = append(ctx, c.Pid)
		}
	}
	return ctx
}

func TestTree(t *testing.T) {
	start := time.Now()
	_, root := GetPsTree([]int32{
		2925089, 2925087, 2947677, 2925085, 2927231, 2925091, 2927238, 2927228, 2927236, 2927226, 2924226, 2925088, 2947517, 2927224, 2924385, 2925086, 2924872, 2925092, 2925090, 2927219, 2927237,
	})
	d := time.Since(start)
	tree := tree.New()
	tree.Root(fmt.Sprintf("%d: %s", root.Pid, root.Cmd))
	t.Logf("%d ms\n", d.Milliseconds())
	so := make([]int32, 0, 128)
	so = ff(tree, root, so)
	d = time.Since(start)
	t.Logf("%d ms\n", d.Milliseconds())
	st := lipgloss.NewStyle().MaxWidth(100)
	t.Logf("\n%s", st.Render(tree.String()))
	t.Logf("%+v \n", so)
}

func TestAddChilds(t *testing.T) {
	style := lipgloss.NewStyle().Inline(true).MaxWidth(10).Width(10)
	t.Logf("|%s|", style.Render("01234567890123456789"))
	t.Logf("|%s|", style.Align(lipgloss.Center).Render("01234567"))
}

func TestChild(t *testing.T) {
	p, _ := process.NewProcess(2810755)
	start := time.Now()
	childs, err := p.Children()
	d := time.Since(start)
	if err != nil {
		t.Error(err)
	}
	t.Logf("%d ms \n", d.Milliseconds())
	t.Logf("childs num: %d", len(childs))
}

func TestCHar(t *testing.T) {
	p, err := process.NewProcess(1)
	if err != nil {
		t.Error(err)
	}
	env, err := p.Environ()
	if err != nil {
		t.Errorf("error get env of process: %v", err)
	}
	slices.Sort(env)
	for _, v := range env {
		if v == "" {
			continue
		}
		t.Log(v)
	}
}

func TestSplitN(t *testing.T) {
	t.Logf("%v", strings.SplitN("a=b=c", "=", 2))
}

func TestReg(t *testing.T) {
	var RegUserPublic = regexp.MustCompile(`^(?i)/public[0-9]*/home/(?:public_user|locauser|localuser)/([0-9a-z_]+)(?:|/.*)$`)
	test := []string{"/public/home/public_user/chenxi/WAN", "/Public/Liming6/hello"}
	for _, v := range test {
		if RegUserPublic.MatchString(v) {
			f := RegUserPublic.FindStringSubmatch(v)
			t.Logf("match %s, %v", v, f)
		} else {
			t.Logf("not match %s", v)
		}
	}

}

func TestSpf(t *testing.T) {
	s := []int{1, 2, 3, 4}
	t.Log(strings.ReplaceAll(fmt.Sprintf("%v", s), " ", ","))
}
