package tool

import (
	"reflect"
	"sort"
)

// RemoveDuplicates 去除string重复元素
func RemoveDuplicates(slice []string) []string {
	sort.Strings(slice)
	i := 0
	var j int
	for {
		if i >= len(slice)-1 {
			break
		}

		for j = i + 1; j < len(slice) && slice[i] == slice[j]; j++ {
		}
		slice = append(slice[:i+1], slice[j:]...)
		i++
	}
	return slice
}

// RemoveDuplicatesInt 去除int重复元素
func RemoveDuplicatesInt(slice []int) []int {
	sort.Ints(slice)
	i := 0
	var j int
	for {
		if i >= len(slice)-1 {
			break
		}

		for j = i + 1; j < len(slice) && slice[i] == slice[j]; j++ {
		}
		slice = append(slice[:i+1], slice[j:]...)
		i++
	}
	return slice
}

// SliceRemoveDuplicates 移除重复元素
func SliceRemoveDuplicates[K comparable](sli []K) (resp []K) {
	sliMap := make(map[K]struct{})
	for i, v := range sli {
		if i > len(sli)-1 {
			break
		}

		if _, ok := sliMap[v]; !ok {
			resp = append(resp, v)
			sliMap[v] = struct{}{}
		}
	}

	return resp
}

// ArrayDiff 获取数组差集元素
func ArrayDiff(array1 []int64, othersParams ...[]int64) ([]int64, error) {
	if len(array1) == 0 {
		return []int64{}, nil
	}
	if len(array1) > 0 && len(othersParams) == 0 {
		return array1, nil
	}
	var tmp = make(map[int64]int, len(array1))
	for _, v := range array1 {
		tmp[v] = 1
	}
	for _, param := range othersParams {
		for _, arg := range param {
			if tmp[arg] != 0 {
				tmp[arg]++
			}
		}
	}
	var res = make([]int64, 0, len(tmp))
	for k, v := range tmp {
		if v == 1 {
			res = append(res, k)
		}
	}
	return res, nil
}

// ArrayIntersect 获取数组交集元素
func ArrayIntersect(array1 []int64, othersParams ...[]int64) ([]int64, error) {
	if len(array1) == 0 {
		return []int64{}, nil
	}
	if len(array1) > 0 && len(othersParams) == 0 {
		return array1, nil
	}
	var tmp = make(map[int64]int, len(array1))
	for _, v := range array1 {
		tmp[v] = 1
	}
	for _, param := range othersParams {
		for _, arg := range param {
			if tmp[arg] != 0 {
				tmp[arg]++
			}
		}
	}
	var res = make([]int64, 0, len(tmp))
	for k, v := range tmp {
		if v > 1 {
			res = append(res, k)
		}
	}
	return res, nil
}

// Columns 获取一个切片里面每个对象的值组成一个新数组并返回
func Columns[K comparable, V any](key string, values []V) (resp []K) {
	resp = make([]K, 0, len(values))
	for i := range values {
		ele := values[i]

		t := reflect.TypeOf(ele)
		v := reflect.ValueOf(ele)
		for t.Kind() == reflect.Pointer {
			t = t.Elem()
			v = v.Elem()
		}

		if result, ok := v.FieldByName(key).Interface().(K); ok {
			resp = append(resp, result)
		}

	}
	return
}

// ColumnsFilter 获取每列元素不等于false的值
func ColumnsFilter[K comparable, V any](key string, values []V) (resp []K) {
	resp = make([]K, 0, len(values))
	for i := range values {
		ele := values[i]

		t := reflect.TypeOf(ele)
		v := reflect.ValueOf(ele)
		for t.Kind() == reflect.Pointer {
			t = t.Elem()
			v = v.Elem()
		}

		val := v.FieldByName(key)
		if result, ok := val.Interface().(K); ok {
			if !val.IsZero() {
				resp = append(resp, result)
			}
		}
	}
	return
}

// ArrayFilter 通过过滤函数过滤数组元素
func ArrayFilter[V any](values []V, callback func(v any) bool) (resp []V) {
	resp = make([]V, 0, len(values))
	for i := range values {
		ele := values[i]

		t := reflect.TypeOf(ele)
		v := reflect.ValueOf(ele)
		for t.Kind() == reflect.Ptr {
			t = t.Elem()
			v = v.Elem()
		}

		if callback != nil {
			if callback(ele) {
				resp = append(resp, ele)
			}
		} else {
			if !v.IsZero() {
				resp = append(resp, ele)
			}
		}
	}
	return
}

// ColumnsUnique 获取一个切片里面每个对象某个字段（key）的值组成一个新数组，并且去重
func ColumnsUnique[K comparable, V any](key string, values []V) (resp []K) {
	return SliceRemoveDuplicates(Columns[K](key, values))
}

// KeyBy 根据key得到一个map
func KeyBy[K comparable, V any](key string, values []V) map[K]V {
	resp := make(map[K]V, len(values))

	for i := range values {
		ele := values[i]

		t := reflect.TypeOf(ele)
		v := reflect.ValueOf(ele)
		for t.Kind() == reflect.Pointer {
			t = t.Elem()
			v = v.Elem()
		}

		if result, ok := v.FieldByName(key).Interface().(K); ok {
			resp[result] = ele
		}
	}

	return resp
}

func GroupBy[K comparable, V any](key string, values []V) map[K][]V {
	resp := make(map[K][]V)

	for i := range values {
		ele := values[i]

		t := reflect.TypeOf(ele)
		v := reflect.ValueOf(ele)
		for t.Kind() == reflect.Pointer {
			t = t.Elem()
			v = v.Elem()
		}

		if result, ok := v.FieldByName(key).Interface().(K); ok {
			resp[result] = append(resp[result], ele)
		}
	}

	return resp
}

// ObjectToMap 从对象里得到键值对
func ObjectToMap[K comparable, L any, V any](keyName, valueName string, values []V) (resp map[K]L) {
	resp = make(map[K]L)
	for i := range values {
		ele := values[i]

		t := reflect.TypeOf(ele)
		v := reflect.ValueOf(ele)
		for t.Kind() == reflect.Pointer {
			t = t.Elem()
			v = v.Elem()
		}

		result1, ok1 := v.FieldByName(keyName).Interface().(K)
		result2, ok2 := v.FieldByName(valueName).Interface().(L)
		if ok1 && ok2 {
			resp[result1] = result2
		}
	}
	return
}

func Query[K comparable](values []K) map[K]K {
	if len(values)%2 != 0 {
		return nil
	}
	resp := make(map[K]K, len(values))
	for i := 0; i < len(values); i += 2 {
		resp[values[i]] = values[i+1]
	}
	return resp
}

func PickValue[K comparable](values []K) []K {
	if len(values)%2 != 0 {
		return nil
	}
	var resp []K
	for i := 0; i < len(values); i += 2 {
		resp = append(resp, values[i+1])
	}
	return resp
}

// InArray 判断元素是否在数组或切片中 (相较泛型更灵活, needle 和 item 类型不必强相等)
func InArray(needle, haystack any) bool {
	haystackValue := reflect.ValueOf(haystack)
	if (haystackValue.Kind() != reflect.Slice && haystackValue.Kind() != reflect.Array) || haystackValue.Len() == 0 {
		return false
	}

	needleValue := reflect.ValueOf(needle)
	for i := 0; i < haystackValue.Len(); i++ {
		item := haystackValue.Index(i).Interface()
		itemValue := reflect.ValueOf(item)

		// 如果 needle 和 item 值相同，或者能够将 needle 转换为 item 的类型并且值相同，则返回 true
		if needleValue.Interface() == item || needleValue.Convert(itemValue.Type()).Interface() == item {
			return true
		}
	}
	return false
}

// InSlice 判断元素是否在切片中,泛型版(性能可能更好)
func InSlice[K comparable](needle K, haystack []K) bool {
	for i := 0; i < len(haystack); i++ {
		if needle == haystack[i] {
			return true
		}
	}
	return false
}

// MapHasFieldVal 获取 map 中的某个字段的值
func MapHasFieldVal[K comparable, V any](m map[K]V, key K) V {
	val, ok := m[key]
	if !ok {
		// 返回 V 类型的零值
		return reflect.Zero(reflect.TypeOf(val)).Interface().(V)
	}
	return val
}

// RemoveValue 切片去除指定值
func RemoveValue[T comparable](slice []T, value T) []T {
	result := make([]T, 0, len(slice))
	for _, v := range slice {
		if v != value {
			result = append(result, v)
		}
	}
	return result
}

func Merge[T comparable](slices ...[]T) []T {
	totalLen := 0
	for _, slice := range slices {
		totalLen += len(slice)
	}
	result := make([]T, totalLen)
	index := 0
	for _, slice := range slices {
		copy(result[index:], slice)
		index += len(slice)
	}
	return result
}

// Chunk 分批
func Chunk[T any](slice []T, size int) [][]T {
	var resp [][]T
	for i := 0; i < len(slice); i += size {
		end := i + size
		if end > len(slice) {
			end = len(slice)
		}
		resp = append(resp, slice[i:end])
	}
	return resp
}

func Intersect[T comparable](s1, s2 []T) []T {
	m := make(map[T]bool)
	for _, v := range s1 {
		m[v] = true
	}
	intersection := make([]T, 0)
	for _, v := range s2 {
		if m[v] {
			intersection = append(intersection, v)
		}
	}
	return intersection
}

func Union[T comparable](s1, s2 []T) []T {
	m := make(map[T]bool)
	for _, v := range s1 {
		m[v] = true
	}
	for _, v := range s2 {
		if !m[v] {
			m[v] = true
		}
	}
	union := make([]T, 0, len(m))
	for k := range m {
		union = append(union, k)
	}
	return union
}

func Difference[T comparable](s1, s2 []T) []T {
	m := make(map[T]bool)
	for _, v := range s2 {
		m[v] = true
	}
	diff := make([]T, 0)
	for _, v := range s1 {
		if !m[v] {
			diff = append(diff, v)
		}
	}
	return diff
}
