// Patience sorting is a sorting algorithm inspired by the card game patience.
//
// For more details check out those links below here:
// GeeksForGeeks article : https://www.geeksforgeeks.org/patience-sorting/
// Wikipedia article: https://en.wikipedia.org/wiki/Patience_sorting
// authors [guuzaa](https://github.com/guuzaa)
// see patiencesort.go

package sort

import "github.com/TheAlgorithms/Go/constraints"

func Patience[T constraints.Ordered](arr []T) []T {
	if len(arr) <= 1 {
		return arr
	}

	var piles [][]T

	for _, card := range arr {
		left, right := 0, len(piles)
		for left < right {
			mid := left + (right-left)/2
			if piles[mid][len(piles[mid])-1] >= card {
				right = mid
			} else {
				left = mid + 1
			}
		}

		if left == len(piles) {
			piles = append(piles, []T{card})
		} else {
			piles[left] = append(piles[left], card)
		}
	}

	return mergePiles(piles)
}

func mergePiles[T constraints.Ordered](piles [][]T) []T {
	var ret []T

	for len(piles) > 0 {
		minID := 0
		minValue := piles[minID][len(piles[minID])-1]

		for i := 1; i < len(piles); i++ {
			if minValue <= piles[i][len(piles[i])-1] {
				continue
			}

			minValue = piles[i][len(piles[i])-1]
			minID = i
		}

		ret = append(ret, minValue)

		piles[minID] = piles[minID][:len(piles[minID])-1]

		if len(piles[minID]) == 0 {
			piles = append(piles[:minID], piles[minID+1:]...)
		}
	}

	return ret
}
