package slice

import (
	"github.com/fthvgb1/wp-go/helper/number"
	"reflect"
	"testing"
)

func TestPagination(t *testing.T) {
	arr := number.Range[int](1, 10, 1)
	type args struct {
		arr      []int
		page     int
		pageSize int
	}
	tests := []struct {
		name string
		args args
		want []int
	}{
		{
			name: "t1",
			args: args{
				arr:      arr,
				page:     1,
				pageSize: 2,
			},
			want: number.Range[int](1, 2, 1),
		}, {
			name: "t2",
			args: args{
				arr:      arr,
				page:     2,
				pageSize: 2,
			},
			want: number.Range[int](3, 4, 1),
		}, {
			name: "t3",
			args: args{
				arr:      arr,
				page:     4,
				pageSize: 3,
			},
			want: []int{10},
		}, {
			name: "t4",
			args: args{
				arr:      arr,
				page:     5,
				pageSize: 3,
			},
			want: []int{},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Pagination(tt.args.arr, tt.args.page, tt.args.pageSize); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Pagination() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestReduce(t *testing.T) {
	type args struct {
		arr []int
		fn  func(int, int) int
		r   int
	}
	tests := []struct {
		name string
		args args
		want int
	}{
		{
			name: "t1",
			args: args{arr: number.Range(1, 10, 1), fn: func(i int, i2 int) int {
				return i + i2
			}},
			want: 55,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Reduce(tt.args.arr, tt.args.fn, tt.args.r); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Reduce() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestFilter(t *testing.T) {
	type args struct {
		arr []int
		fn  func(int) bool
	}
	tests := []struct {
		name string
		args args
		want []int
	}{
		{
			name: "t1",
			args: args{arr: number.Range(1, 10, 1), fn: func(i int) bool {
				return i > 4
			}},
			want: number.Range(5, 10, 1),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Filter(tt.args.arr, tt.args.fn); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Filter() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestMap(t *testing.T) {
	type args struct {
		arr []int8
		fn  func(int8) int
	}
	tests := []struct {
		name string
		args args
		want []int
	}{
		{
			name: "t1",
			args: args{
				arr: number.Range[int8](1, 10, 1),
				fn: func(i int8) int {
					return int(i)
				},
			},
			want: number.Range(1, 10, 1),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Map(tt.args.arr, tt.args.fn); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Map() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestReverse(t *testing.T) {
	type args struct {
		arr []int
	}
	tests := []struct {
		name string
		args args
		want []int
	}{
		{
			name: "t1",
			args: args{arr: number.Range(1, 10, 1)},
			want: number.Range(10, 1, -1),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Reverse(tt.args.arr); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Reverse() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestSlice(t *testing.T) {
	type args struct {
		arr    []int
		offset int
		length int
	}
	tests := []struct {
		name  string
		args  args
		wantR []int
	}{
		{
			name: "t1",
			args: args{
				arr:    number.Range(1, 10, 1),
				offset: 3,
				length: 2,
			},
			wantR: number.Range(4, 5, 1),
		},
		{
			name: "t2",
			args: args{
				arr:    number.Range(1, 10, 1),
				offset: 3,
				length: 0,
			},
			wantR: number.Range(4, 10, 1),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if gotR := Slice(tt.args.arr, tt.args.offset, tt.args.length); !reflect.DeepEqual(gotR, tt.wantR) {
				t.Errorf("Slice() = %v, want %v", gotR, tt.wantR)
			}
		})
	}
}

func TestComb(t *testing.T) {
	type args struct {
		arr []int
		m   int
	}
	tests := []struct {
		name  string
		args  args
		wantR [][]int
	}{
		{
			name: "t1",
			args: args{
				arr: number.Range(1, 5, 1),
				m:   2,
			},
			wantR: [][]int{
				{1, 2},
				{1, 3},
				{1, 4},
				{1, 5},
				{2, 3},
				{2, 4},
				{2, 5},
				{3, 4},
				{3, 5},
				{4, 5},
			},
		},
		{
			name: "t2",
			args: args{
				arr: number.Range(1, 5, 1),
				m:   3,
			},
			wantR: [][]int{
				{1, 2, 3},
				{1, 2, 4},
				{1, 2, 5},
				{1, 3, 4},
				{1, 3, 5},
				{1, 4, 5},
				{2, 3, 4},
				{2, 3, 5},
				{2, 4, 5},
				{3, 4, 5},
			},
		},
		{
			name: "t3",
			args: args{
				arr: number.Range(1, 5, 1),
				m:   4,
			},
			wantR: [][]int{
				{1, 2, 3, 4},
				{1, 2, 3, 5},
				{1, 2, 4, 5},
				{1, 3, 4, 5},
				{2, 3, 4, 5},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if gotR := Comb(tt.args.arr, tt.args.m); !reflect.DeepEqual(gotR, tt.wantR) {
				t.Errorf("Comb() = %v, want %v", gotR, tt.wantR)
			}
		})
	}
}

func TestChunk(t *testing.T) {
	type args struct {
		arr  []int
		size int
	}
	tests := []struct {
		name string
		args args
		want [][]int
	}{
		{
			name: "t1",
			args: args{
				arr:  number.Range(1, 7, 1),
				size: 2,
			},
			want: [][]int{{1, 2}, {3, 4}, {5, 6}, {7}},
		},
		{
			name: "t2",
			args: args{
				arr:  number.Range(1, 8, 1),
				size: 2,
			},
			want: [][]int{{1, 2}, {3, 4}, {5, 6}, {7, 8}},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Chunk(tt.args.arr, tt.args.size); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Chunk() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestSimpleSliceToMap(t *testing.T) {
	type args struct {
		arr []int
		fn  func(int) int
	}
	tests := []struct {
		name string
		args args
		want map[int]int
	}{
		{
			name: "t1",
			args: args{arr: []int{1, 2, 3}, fn: func(i int) int {
				return i
			}},
			want: map[int]int{1: 1, 2: 2, 3: 3},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := SimpleToMap(tt.args.arr, tt.args.fn); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("SimpleToMap() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestToMap(t *testing.T) {
	type ss struct {
		id int
		v  string
	}
	type args struct {
		arr         []ss
		fn          func(ss) (int, ss)
		isCoverPrev bool
	}
	tests := []struct {
		name string
		args args
		want map[int]ss
	}{
		{
			name: "t1",
			args: args{
				arr: []ss{{1, "k1"}, {2, "v2"}, {2, "v3"}},
				fn: func(s ss) (int, ss) {
					return s.id, s
				},
				isCoverPrev: true,
			},
			want: map[int]ss{1: {1, "k1"}, 2: {2, "v3"}},
		}, {
			name: "t2",
			args: args{
				arr: []ss{{1, "k1"}, {2, "v2"}, {2, "v3"}},
				fn: func(s ss) (int, ss) {
					return s.id, s
				},
				isCoverPrev: false,
			},
			want: map[int]ss{1: {1, "k1"}, 2: {2, "v2"}},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ToMap(tt.args.arr, tt.args.fn, tt.args.isCoverPrev); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("ToMap() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestReverseSelf(t *testing.T) {
	type args struct {
		arr []int
	}
	tests := []struct {
		name string
		args args
		want []int
	}{
		{
			name: "t1",
			args: args{
				arr: number.Range(1, 10, 1),
			},
			want: number.Range(10, 1, -1),
		}, {
			name: "t2",
			args: args{
				arr: number.Range(1, 9, 1),
			},
			want: number.Range(9, 1, -1),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ReverseSelf(tt.args.arr); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("ReverseSelf() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestFilterAndMap(t *testing.T) {
	type a struct {
		x int
		y string
	}

	type args[T any, N any] struct {
		arr []T
		fn  func(T) (N, bool)
	}
	type testCase[T any, N any] struct {
		name  string
		args  args[T, N]
		wantR []N
	}
	tests := []testCase[a, string]{
		{
			name: "t1",
			args: args[a, string]{
				arr: []a{
					{1, "1"}, {2, "2"}, {3, "3"},
				},
				fn: func(t a) (r string, ok bool) {
					if t.x > 2 {
						r = t.y
						ok = true
					}
					return
				},
			},
			wantR: []string{"3"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if gotR := FilterAndMap[string](tt.args.arr, tt.args.fn); !reflect.DeepEqual(gotR, tt.wantR) {
				t.Errorf("FilterAndMap() = %v, want %v", gotR, tt.wantR)
			}
		})
	}
}
