package ii

import (
	"fmt"
	"reflect"
	"strings"
	"testing"
	"time"

	"git.simanc.com/software/golib/v4/features/mo"
	"git.simanc.com/software/golib/v4/gnet"
)

func TestFieldInfo_ConvertDouble(t *testing.T) {
	field := FieldInfo{
		Name:    "ConvertDouble",
		Type:    mo.TypeDouble,
		Decimal: 3,
	}
	val := []any{
		400.1516,
		-400,
		float64(0), float32(0), 0, int8(0), int16(0), int32(0), int64(0), uint(0), uint8(0), uint16(0), uint32(0), uint64(0),
		"12345.125",
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertString(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertString",
		Type: mo.TypeString,
	}
	val := []any{
		"TestString",
		true,
		float64(3.1415926), float32(3.1415926), 100, int8(100), int16(100), int32(100), int64(100), uint(100), uint8(100), uint16(100), uint32(100), uint64(100),
		mo.M{"field": "string"},
		[]string{"Test", "String"},
		[4]any{"Test", true, float64(3.1415926), int64(100)},
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertObject(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertObject",
		Type: mo.TypeObject,
		Fields: []FieldInfo{
			{
				Name: "name",
				Type: mo.TypeString,
			},
			{
				Name: "age",
				Type: mo.TypeInt64,
			},
		},
	}
	val := []any{
		mo.M{"name": "ConvertObject", "age": 111},
		map[string]any{"name": "string"},
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertArray(t *testing.T) {
	field := FieldInfo{
		Name:  "ConvertArray",
		Type:  mo.TypeArray,
		Items: FieldItemsDefault,
	}
	val := []any{
		mo.A{"111", 222, true},
		[3]int{0, 1, 2},
		"[111,222,333]",
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Len(), reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertArrayItemObject(t *testing.T) {
	field := FieldInfo{
		Name:   "ConvertArrayItemObject",
		Type:   mo.TypeArray,
		Items:  FieldItemsObject,
		Fields: []FieldInfo{{Name: "name", Type: mo.TypeString}},
	}
	val := []any{
		[]any{mo.M{"name": "xiaoming"}},
		`{"name":"xiaoming"}`,
		`[{"name":"xiaoming"}]`,
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Len(), reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertArrayItemObjectID(t *testing.T) {
	field := FieldInfo{
		Name:  "ConvertArrayItemObjectID",
		Type:  mo.TypeArray,
		Items: FieldItemsObjectId,
	}
	val := []any{
		[]any{mo.ID.New()},
		[]any{mo.ID.New().Hex(), mo.ID.New().Hex()},
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Len(), reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertBinData(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertBinData",
		Type: mo.TypeBinary,
	}
	val := []any{
		byte(1),
		[]byte{1, 2, 3},
		[3]byte{0x01, 0x02, 0x03},
		"0x01 0x02 0x03",
		mo.Binary{Data: []byte{0x01, 0x02, 0x03}},
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log("Normal:", rv, reflect.ValueOf(rv).Type().Kind())
	}
	// 使用指针传入时
	cs := [3]byte{0x01, 0x02, 0x03}
	rv, err := field.Convert(&cs)
	if err != nil {
		t.Error(err)
		return
	}
	v := rv.(mo.Binary)
	v.Data[2] = 0x6
	t.Log("Pointer:   ", rv, reflect.ValueOf(rv).Type().Kind())
	t.Log("PointerMod:", v, reflect.ValueOf(v).Type().Kind())
}

func TestFieldInfo_ConvertObjectId(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertObjectId",
		Type: mo.TypeObjectId,
	}
	val := []any{
		mo.ID.New(),
		"63b4e0de62b30179734f7982",
		"new",
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertBoolean(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertBoolean",
		Type: mo.TypeBoolean,
	}
	val := []any{
		true,
		"true",
		float64(1), float32(1), 1, int8(1), int16(1), int32(1), int64(1), uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestCovertDateTime(t *testing.T) {
	t.Log(strings.Split("2023", ","))
	md, err := mo.NewDateTime().MarshalJSON()
	if err != nil {
		t.Error(err)
		return
	}
	t.Log(string(md))
	t.Log(time.Now().Format(mo.ISODate))
}

func TestFieldInfo_ConvertDatetime(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertDate",
		Type: mo.TypeDateTime,
	}
	tn := time.Now()

	b := make([]byte, 8)
	gnet.BigEndian.PutUint64(b, uint64(tn.UnixMilli()))

	val := []any{
		"now",
		mo.NewDateTimeFromTime(tn),
		tn,
		1 * time.Minute,
		tn.Format(mo.ISODate),
		fmt.Sprintf("%d", tn.UnixMilli()),
		b,
		float64(1), float32(1), 1, int8(1), int16(1), int32(1), int64(1), uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertInt(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertInt",
		Type: mo.TypeInt32,
	}
	tn := time.Now()
	val := []any{
		float64(1), float32(1), 1, int8(1), int16(1), int32(1), int64(1), uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
		"1024",
		[]byte{0x01, 0x02, 0x03, 0x04},
		1 * time.Minute,
		mo.NewDateTimeFromTime(tn),
		tn,
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestFieldInfo_ConvertLong(t *testing.T) {
	field := FieldInfo{
		Name: "ConvertLong",
		Type: mo.TypeInt64,
	}
	tn := time.Now()
	val := []any{
		float64(1), float32(1), 1, int8(1), int16(1), int32(1), int64(1), uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
		"1024",
		[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
		1 * time.Minute,
		mo.NewDateTimeFromTime(tn),
		tn,
	}
	for _, v := range val {
		rv, err := field.Convert(v)
		if err != nil {
			t.Error(err)
			return
		}
		t.Log(rv, reflect.ValueOf(rv).Type().Kind())
	}
}

func TestLenSlice(t *testing.T) {
	v := []string{"11", "22", "33"}
	n := make([]any, len(v))
	length := reflect.ValueOf(v).Len()
	for i := 0; i < length; i++ {
		n[i] = reflect.ValueOf(v).Index(i).Interface()
	}
	t.Log(v)
	t.Log(n)
}

func TestGetTypeFromAny(t *testing.T) {
	b := gnet.String("01 02")
	t.Log(b.Hex())
	t.Log(b.ToBytes())
}
