package utils

/*
return a new slice with len = cap
*/
func SliceCopy[T any](src []T) []T {
	if src == nil { return nil }
	dst := make([]T, len(src))
	copy(dst, src)
	return dst
}

/*
	fn return true to append V
*/
func SliceTransform[T, V any](src []T, fn func(int, T) (V, bool)) []V {
	r := make([]V, 0, len(src))
	for i, v := range src {
		if n, ok := fn(i, v); ok {
			r = append(r, n)
		}
	}
	return r
}

func Reverse[S ~[]E, E any](s S) {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
}

func MapKeys[M ~map[K]V, K comparable, V any](m M) []K {
	ln := len(m)
	if ln == 0 { return nil }
	r := make([]K, 0, ln)
	for k := range m {
		r = append(r, k)
	}
	return r
}
func MapValues[M ~map[K]V, K comparable, V any](m M) []V {
	r := make([]V, 0, len(m))
	for _, v := range m {
		r = append(r, v)
	}
	return r
}
func MapKeyAndValues[M ~map[K]V, K comparable, V any](m M) (keys []K, values []V) {
	size := len(m)
	keys = make([]K, size)
	values = make([]V, size)
	i := 0
	for k, v := range m {
		keys[i], values[i] = k, v
		i++
	}
	return
}

func MapKeyAndValues2[M ~map[K]V, K comparable, V any, S struct{
	K K 
	V V
}](m M) []S {
	res := make([]S, len(m))
	i := 0
	for k, v := range m {
		res[i] = S{K: k, V: v}
		i++
	}
	return res
}

func MapAdd[M ~map[K1]map[K2]V, K1, K2 comparable, V any](m M, k1 K1, k2 K2, v V) {
	m2 := m[k1]
	if m2 == nil {
		m2 = make(map[K2]V)
		m[k1] = m2
	}
	m2[k2] = v
}

func MapToMap[K1, K2 comparable, V1, V2 any](m map[K1]V1, fn func(K1, V1) (K2, V2, bool)) map[K2]V2 {
	r := make(map[K2]V2, len(m))
	for k1, v1 := range m {
		if k2, v2, ok := fn(k1, v1); ok {
			r[k2] = v2
		}
	}
	return r
}

func KVtoMap[K comparable, V any](s []struct{
	K K
	V V
}) map[K]V {
	res := make(map[K]V)
	for _, i := range s {
		res[i.K] = i.V
	}
	return res
}

// Sort map by value
func SortMapByValue[K comparable, V string | uint | uint8 | uint16 | uint32 | uint64 | int | int8 | int16 | int32 | int64 | float32 | float64](m map[K]V, ascend bool) (keys []K, values []V) {
	keys, values = MapKeyAndValues(m)
	for i := 0; i < len(values)-1; i++ {
		for j := 0; j < len(values)-1-i; j++ {
			if ascend {
				if values[j] > values[j+1] {
					keys[j], keys[j+1] = keys[j+1], keys[j]
					values[j], values[j+1] = values[j+1], values[j]
				}
			} else {
				if values[j] < values[j+1] {
					keys[j], keys[j+1] = keys[j+1], keys[j]
					values[j], values[j+1] = values[j+1], values[j]
				}
			}
		}
	}
	return
}

func MergeMap[K comparable, V any](ms... map[K]V) map[K]V {
	size := 0
	for _, m := range ms {
		size += len(m)
	}
	merged := make(map[K]V, size)
	for _, m := range ms {
		for k, v := range m {
			merged[k] = v
		}
	}
	return merged
}

func SortMapByKey[K string | uint | uint8 | uint16 | uint32 | uint64 | int | int8 | int16 | int32 | int64 | float32 | float64, V any](m map[K]V, ascend bool) (keys []K, values []V) {
	keys, values = MapKeyAndValues(m)
	for i := 0; i < len(keys)-1; i++ {
		for j := 0; j < len(keys)-1-i; j++ {
			if ascend {
				if keys[j] > keys[j+1] {
					keys[j], keys[j+1] = keys[j+1], keys[j]
					values[j], values[j+1] = values[j+1], values[j]
				}
			} else {
				if keys[j] < keys[j+1] {
					keys[j], keys[j+1] = keys[j+1], keys[j]
					values[j], values[j+1] = values[j+1], values[j]
				}
			}
		}
	}
	return
}

type KV[K comparable, V any] struct {
	K K
	V V
}

func MapToSlice[K comparable, V any](m map[K]V) []*KV[K, V] {
	var r []*KV[K, V]
	for k, v := range m {
		r = append(r, &KV[K, V]{K: k, V: v})
	}
	return r
}

/*
	fn return true to append N
*/
func MapExtractSlice[K comparable, V, N any](m map[K]V, fn func(K, V) (N, bool)) []N {
	var r = make([]N, len(m))
	for k, v := range m {
		if n, ok := fn(k, v); ok {
			r = append(r, n)
		}
	}

	if len(r) != len(m) {
		cpy := make([]N, len(r))
		copy(cpy, r)
		return cpy
	} else {
		return r
	}
	
}

func SortSlice[V string | uint | uint8 | uint16 | uint32 | uint64 | int | int8 | int16 | int32 | int64 | float32 | float64](s []V, ascend bool) {
	for i := 0; i < len(s)-1; i++ {
		for j := 0; j < len(s)-1-i; j++ {
			if (ascend && s[j+1] < s[j]) || (!ascend && s[j+1] < s[j]) {
				s[j], s[j+1] = s[j+1], s[j]
			}
		}
	}
}

// 当 func(x, y) = false 时, swap
func SortSliceByFunc[T any](s []T, fn func(x, y T) bool) {
	for i := 0; i < len(s)-1; i++ {
		for j := 0; j < len(s)-1-i; j++ {
			if !fn(s[j], s[j+1]) {
				s[j], s[j+1] = s[j+1], s[j]
			}
		}
	}
}

/*
 按 ref 的顺序排序
*/
func SortSliceByRef[T comparable](s []T, ref []T) {
	fn := func(t T) uint {
		var index = ^uint(0) 
		for i, r := range ref {
			if r == t {
				index = uint(i)
				break
			}
		}
		return index
	}
	SortSliceByFunc(s, func(x, y T) bool {
		return fn(x) < fn (y)
	})
}

func SliceToMap[K comparable, V any](a []K, val V) map[K]V {
	m := make(map[K]V, len(a))
	for _, v := range a {
		m[v] = val
	}
	return m
}

func SliceToMap_byFunc[K comparable, V any](a []V, fn func(int, V) (K, bool)) map[K]V {
	m := make(map[K]V, len(a))
	for i, v := range a {
		if k, ok := fn(i, v); ok {
			m[k] = v
		}
	}
	return m
}

func SliceEqual[V string | uint | uint8 | uint16 | uint32 | uint64 | int | int8 | int16 | int32 | int64 | float32 | float64](x, y []V) bool {
	if len(x) != len(y) {
		return false
	}
	for i := range x {
		if x[i] != y[i] {
			return false
		}
	}
	return true
}

func SliceUnique[K comparable](s []K) []K {
	m := make(map[K]struct{})
	for _, ss := range s {
		m[ss] = struct{}{}
	}
	return MapKeys(m)
}

// 将 tagert 插入到 s 的 at 位置
func SliceInsert[T any](s []T, target T, at int) []T {
	// ln := len(s)
	// if at >= ln {
	// 	return append(s, target)
	// }
	// s = append(s, s[ln-1])
	// for i := ln - 1; i > at; i-- {
	// 	s[i] = s[i-1]
	// }
	// s[at] = target
	if at <= 0 {
		return append([]T{target}, s...)
	} else if at >= len(s) {
		return append(s, target)
	} else {
		newqueue := make([]T, len(s)+1)
		copy(newqueue, s[:at])
		newqueue[at] = target
		copy(newqueue[at+1:], s[at:])
		return newqueue
	}
}

// 删除 slice at 位置的数据
func SliceRemoveAt[T any](s []T, at int) []T {
	if at >= len(s) {
		return s
	}
	return append(s[:at], s[at+1:]...)
}

// fn return true to keep, return false to discard
func SliceFilter[T any](s []T, fn func(int, T) bool) []T {
	var r []T
	for i, t := range s {
		if fn(i, t) {
			r = append(r, t)
		}
	}
	return r
}

// if fn returns true, then is found
func SliceFind[T any](s []T, fn func(T) bool) (T, /*ok*/ bool) {
	for _, t := range s {
		if fn(t) {
			return t, true
		}
	}
	var t T
	return t, false
}

func SliceContain[T comparable](s []T, t T) /*ok*/ bool {
	for _, ss := range s {
		if ss == t {
			return true
		}
	}
	return false
}

func MapMapPush[K1 comparable, K2 comparable, V any](m map[K1]map[K2]V, k1 K1, k2 K2, v V) {
	m2 := m[k1]
	if m2 == nil {
		m2 = make(map[K2]V)

	}
	m2[k2] = v
}
func MapMapGet[K1 comparable, K2 comparable, V any](m map[K1]map[K2]V, k1 K1, k2 K2) V {
	var v V
	m2 := m[k1]
	if m2 == nil {
		return v
	}
	return m2[k2]
}
