package otherutils

import "fmt"

// CompareResult represents the result of slice comparison
type CompareResult int

const (
	Different     CompareResult = -1 // Elements are different
	SameUnordered CompareResult = 0  // Same elements but different order
	SameOrdered   CompareResult = 1  // Same elements in same order
)

// RemoveFirst removes the first element that matches the predicate.
// Note: This function modifies the original slice and does not preserve order
// as it moves the last element to the removed position.
func RemoveFirst[K any](sl []K, f func(v1 K) bool) []K {
	for k, v := range sl {
		if f(v) {
			sl[k] = sl[len(sl)-1]
			return sl[:len(sl)-1]
		}
	}
	return sl
}

// InSlice checks if a slice contains a specific element.
func InSlice[K comparable](src []K, sub K) bool {
	for _, v := range src {
		if v == sub {
			return true
		}
	}
	return false
}

// RemoveSliceOrdered removes the first occurrence of sub from src while preserving order.
// Returns the modified slice.
func RemoveSliceOrdered[K comparable](src []K, sub K) []K {
	for k, v := range src {
		if v == sub {
			copy(src[k:], src[k+1:])
			return src[:len(src)-1]
		}
	}
	return src
}

// RemoveSliceUnordered removes the first occurrence of sub from src.
// Note: This function does not preserve the original order as it moves
// the last element to the removed position for better performance.
func RemoveSliceUnordered[K comparable](src []K, sub K) []K {
	for k, v := range src {
		if v == sub {
			src[k] = src[len(src)-1]
			return src[:len(src)-1]
		}
	}
	return src
}

// RemoveOneFromSlice removes the first occurrence of an element that matches the predicate.
func RemoveOneFromSlice[K any](src []K, cmp func(K) bool) []K {
	for k, v := range src {
		if cmp(v) {
			copy(src[k:], src[k+1:])
			return src[:len(src)-1]
		}
	}
	return src
}

// SubSlice returns a new slice containing elements from src that are not in sub.
// Note: This function modifies the original slice to avoid memory allocation.
// Example: [1,1,2,3] - [1,1,2,4] = [3]
func SubSlice[K comparable](src []K, sub []K) []K {
	// 组织MAP表
	subMap := make(map[K]int, len(sub))
	for _, v := range sub {
		subMap[v] += 1
	}
	remove := func(val K) bool {
		v, ok := subMap[val]
		if !ok {
			return false
		}

		if v > 1 {
			subMap[val] -= 1
		} else {
			delete(subMap, val)
		}
		return true
	}

	index := 0
	for _, v := range src {

		if remove(v) {
			continue
		}

		src[index] = v
		index += 1
	}
	src = src[:index]
	return src
}

// CompareSlice compares two slices and returns the result.
func CompareSlice[K comparable](p1 []K, p2 []K) CompareResult {
	// 长度不等直接-1
	if len(p1) != len(p2) {
		return Different
	}

	// 逐个比较每个相等则为1
	allEq := true
	for k, v := range p1 {
		if v != p2[k] {
			allEq = false
			break
		}
	}
	if allEq {
		return SameOrdered
	}

	// 个数统计，每个相等则为0
	p1Nums := make(map[K]int)
	for _, v := range p1 {
		p1Nums[v] += 1
	}
	p2Nums := make(map[K]int)
	for _, v := range p2 {
		p2Nums[v] += 1
	}
	if len(p1Nums) != len(p2Nums) {
		return Different
	}

	for k, v := range p1Nums {
		n := p2Nums[k]
		if n != v {
			return Different
		}
	}
	return SameUnordered
}

// CompareMap compares two maps and returns true if they are equal, false otherwise.
func CompareMap[K comparable, V comparable](p1 map[K]V, p2 map[K]V) bool {
	//长度不等则为-1
	if len(p1) != len(p2) {
		return false
	}

	for k, v := range p1 {
		n, ok := p2[k]
		if !ok {
			return false
		}
		if n != v {
			return false
		}
	}
	return true
}

func CloneSlice[T any](slice []T) []T {
	newSlice := make([]T, len(slice))
	copy(newSlice, slice)
	return newSlice
}

func TestSlice() {

	//[1,1,2,3] - [1,1,2,4] = [3]
	fmt.Println(SubSlice([]int{1, 1, 2, 3}, []int{1, 1, 2, 4}))

	fmt.Println(SubSlice([]int{1, 1, 2, 3}, []int{}))

	fmt.Println(SubSlice([]int{}, []int{1, 1, 2, 4}))

}
