package rest

import (
	"log"
	"reflect"
	"strings"
	"testing"
	"time"

	"git.ali33.ru/fcg-xvii/go-tools/json"
)

func TestFieldsDefault(t *testing.T) {
	type RR struct {
		ID      int64  `rest:"default"`
		Name    string `rest:"default"`
		GroupID int64
	}

	rr := RR{}
	fields := fieldsDefault(reflect.TypeOf(rr))
	//log.Println(*fields[0])
	expected := []any{"id", "name"}
	if len(fields) != len(expected) {
		t.Errorf("expected %v, real %v", expected, fields)
	}
	for i, val := range expected {
		if fields[i] != val {
			t.Errorf("expected %v, real %v", expected, fields)
		}
	}
}

//////////////////////////////////////////////////

type FPermissions struct {
	ID       int `rest:"default"`
	ParentID int
	Name     string
}

type FUser struct {
	ID     int
	Name   string
	Group  *FPermissions
	Groups []*FPermissions
}

func TestFieldsList(t *testing.T) {
	u := &FUser{
		ID:   1,
		Name: "okko",
		/*
			Group: &FPermissions{
				ID:       100,
				ParentID: 50,
				Name:     "OGroup",
			},
		*/
		Groups: []*FPermissions{
			{
				ID:       100,
				ParentID: 5,
				Name:     "OGroup",
			},
			{
				ID:       200,
				ParentID: 0,
				Name:     "GGroup",
			},
		},
	}

	fList := FieldList{
		FieldFromName("ID"),
		FieldFromName("Name"),
		&Field{
			Name: "Group",
			Names: []*Field{
				{
					Name: "ID",
				},
			},
		},
		&Field{
			Name: "Groups",
			Names: []*Field{
				{
					Name: "ParentID",
				},
				{
					Name: "Name",
				},
			},
		},
	}

	m, err := Fields(u, nil, fList)
	if err != nil {
		t.Error(err)
	}
	m.LogPretty()
}

func TestFielderName(t *testing.T) {
	name := "Name"
	if field, err := parseName(reflect.ValueOf(name)); field.Name != name || err != nil {
		if err != nil {
			t.Error(err)
		}
		t.Errorf("expected %v, real %v", name, field.Name)
	}
	obj := json.Map{
		"name": "Object",
		"fields": []any{
			"okko",
			"cooler",
		},
	}
	field, err := parseName(reflect.ValueOf(obj))
	if err != nil {
		t.Error(err)
	}
	// check name
	if field.Name != "object" {
		t.Errorf("expected %v, real %v", "object", name)
	}
	// check fields
	for i, val := range []any{"okko", "cooler"} {
		if field.Names[i] != val {
			t.Errorf("expected %v, real %v", val, field.Names[i])
		}
	}
}

type RR struct {
	ID      int64  `rest:"default"`
	Name    string `rest:"default"`
	GroupID int64  `rest:"ignore"`
	Child   *RR
	Nums    []int64
	Childs  []*RR
	MM      json.Map
}

func (s *RR) RestFields(result json.Map, fields FieldList) {
	if _, check := fields.Field("group_id"); check {
		result["group_id"] = s.GroupID * 1000
	}
}

func TestFielderVal(t *testing.T) {
	rr := &RR{
		ID:      1,
		Name:    "okko",
		GroupID: 2,
		MM: json.Map{
			"one": 1,
			"obj": &RR{
				ID:   1,
				Name: "mm-obj",
			},
		},
		Child: &RR{
			ID:      3,
			Name:    "cooler",
			GroupID: 4,
		},
		Nums: []int64{1, 2, 3},
		Childs: []*RR{
			{
				ID:      5,
				Name:    "okko1",
				GroupID: 6,
			},
			{
				ID:      7,
				Name:    "cooler1",
				GroupID: 8,
			},
		},
	}

	fList := FieldListFromObjects(
		"id",
		"name",
		"nums",
		"group_id",
		"mm",
		json.Map{
			"name":   "childs",
			"fields": []any{"id", "name", "childs"},
		},
		json.Map{
			"name":   "child",
			"fields": []any{"id"},
		},
	)

	val, err := fieldVal(
		reflect.ValueOf(rr),
		"",
		nil,
		fList,
	)
	if err != nil {
		t.Error(err, err.Args())
	}

	m := val.Interface().(json.Map)
	m.LogPretty()

	rfList := FieldListFromObjects(
		"id",
		"name",
		"nums",
		"mm",
		"group_id",
		json.Map{
			"name":   "childs",
			"fields": []any{"id", "name", "childs"},
		},
		json.Map{
			"name":   "child",
			"fields": []any{"id"},
		},
	)

	mVal, err := Fields(
		rr,
		nil,
		rfList,
	)
	if err != nil {
		t.Error(err, err.Args())
	}
	log.Println("========================================")
	mVal.LogPretty()
}

type RTime struct {
	Time
}

type TimeObj struct {
	Created RTime `rest:"default"`
}

func TestTime(t *testing.T) {
	obj := TimeObj{
		Created: RTime{Time(time.Now())},
	}
	log.Println(obj)
	f, _ := Fields(&obj, nil, nil)
	f.LogPretty()

	var rObj TimeObj
	if err := Serialize(f, &rObj); err != nil {
		t.Fatal(err.Map().JSONPrettyString())
	}
	log.Println(rObj)
	jm := json.Map{
		"created": 12321311,
	}
	if err := Serialize(jm, &rObj); err != nil {
		t.Fatal(err.Map().JSONPrettyString())
	}
	t.Log(rObj)
}

type LObj struct {
	ID      int64     `rest:"default"`
	Name    string    `rest:"default"`
	Created time.Time `rest:"default"`
}

type LList struct {
	Result []*LObj `rest:"fixed"`
}

func (s *LList) RestFields(fieldName string, names ...any) (any, IErrorArgs) {
	if fieldName == "" {
		fList := FieldListFromObjects(names...)
		l, err := FieldsAny(&s.Result, nil, fList)
		if err != nil {
			return nil, err
		}
		rm := json.Map{
			"llist": l,
		}
		return rm, nil
	}
	return nil, ErrorFiled(fieldName, "field is not exists")
}

func TestFielderList(t *testing.T) {
	obj := &LList{
		Result: []*LObj{
			{
				ID:      1,
				Name:    "Val 1",
				Created: time.Now(),
			},
			{
				ID:   2,
				Name: "Val 2",
			},
		},
	}

	m, err := Fields(obj, nil, FieldListFromObjects("id"))
	if err != nil {
		t.Fatal(err)
	}
	m.LogPretty()
}

type RRequest struct {
	Count int
	Okko  string `rest:"required"`
}

type Tickers struct {
	*RRequest
	Cool      *RRequest
	TickerIDS []string
}

func TestSerializeRaw(t *testing.T) {
	m := json.Map{
		"ticker_ids": []string{"1", "2", "3"},
		"okko":       "10",
	}
	var ti Tickers
	if err := Serialize(m, &ti); err != nil {
		t.Fatal(err)
	}
	log.Println(ti.TickerIDS)
	log.Println(ti.RRequest)
	log.Println(ti.Cool)
}

func TestServer(t *testing.T) {

}

func TestFieldKeys(t *testing.T) {
	l := []any{
		"id",
		"name",
		json.Map{
			"name": "parent",
			"fields": []any{
				"id",
				"name",
				json.Map{
					"name":   "child1",
					"fields": []any{},
				},
				json.Map{
					"name": "child2",
					"fields": []any{
						"one",
					},
				},
			},
		},
	}

	jm := ObjectFieldKeys(l)
	jm.LogPretty()
}

type FieldNamesTest struct {
	ID       int
	Name     string
	ParentID int
}

func TestFieldNames(t *testing.T) {
	v := FieldNamesTest{
		ID:       10,
		Name:     "Namerrrr",
		ParentID: 1,
	}

	var iv any = &v

	fields, err := FieldNames(iv)

	if err != nil {
		t.Fatal(err)
	}

	t.Log(fields)
}

type User struct {
	ID       int
	Name     string
	Created  time.Time
	ParentID *int
}

type AuthEmail struct {
	Category  json.Map
	Email     string `rest:"required" example:"mail@mail.ml"`
	ThemeName string `rest:"required"`
	UUser     *User
	Fields    []any
}

func (s *AuthEmail) Validate(req IRequestIn) IRequestOut {
	s.Email = strings.TrimSpace(s.Email)
	return nil
}

// AuthEmail godoc
//
//	@Summary		Автризация при помощи email
//	@Description	Если пользователь не существует, он будет создан
//	@Description	После выполнения команды на указанный email отправляется письмо с кодом,
//	@Description	который необходимо обменять на токен авторизации
//	@Tags			client
//	@Accept			json
//	@Produce		json
//	@Param object body AuthEmail true "Входные параметры"
//	@Success		200			{object}	result.ResultOK	"result"
//	@Router			/users/auth_email [post]
func (s *AuthEmail) Execute(req IRequestIn) IRequestOut {
	return req.OutSuccess(json.Map{}, nil)
}

func TestSerializeEmail(t *testing.T) {
	m := json.Map{
		"Category":  nil,
		"email":     "flint@77i.su",
		"themeName": "th-name",
		"UUser": json.Map{
			"ID": 100,
			//"Name":     "User 100",
			"Created":  "10.11.1983 03:12",
			"ParentID": nil,
		},
	}

	r := &AuthEmail{}

	err := Serialize(m, r)
	if err != nil {
		t.Fatal(err)
	}

	t.Log(r, *r.UUser, r.UUser.ParentID)
	//t.Log(*r.UUser.ParentID)

}

func TestFielderMap(t *testing.T) {
	m := json.Map{
		"one": 1,
		"two": 2,
	}
	rm, err := Fields(m, nil, nil)
	if err != nil {
		t.Fatal(err)
	}
	rm.LogPretty()
}