package slowquery

import (
	"container/heap"
)

type slowLogsHeap struct {
	limit int
	h     heap.Interface
}

func newSlowLogsHeap(orderBy string, desc bool, limit int) *slowLogsHeap {
	var h heap.Interface
	switch orderBy {
	case "query_time":
		if desc {
			h = &slowLogsOrderByQueryTimeAscHeap{}
		} else {
			h = &slowLogsOrderByQueryTimeDescHeap{}
		}
	case "memory_max":
		if desc {
			h = &slowLogsOrderByMemMaxAscHeap{}
		} else {
			h = &slowLogsOrderByMemMaxDescHeap{}
		}
	case "total_keys":
		if desc {
			h = &slowLogsOrderByTotalKeysAscHeap{}
		} else {
			h = &slowLogsOrderByTotalKeysDescHeap{}
		}
	case "process_keys":
		if desc {
			h = &slowLogsOrderByProcessKeysAscHeap{}
		} else {
			h = &slowLogsOrderByProcessKeysDescHeap{}
		}
	default:
		if desc {
			h = &slowLogsOrderByTimestampAscHeap{}
		} else {
			h = &slowLogsOrderByTimestampDescHeap{}
		}
	}
	heap.Init(h)
	return &slowLogsHeap{
		h:     h,
		limit: limit,
	}
}

func (h *slowLogsHeap) Push(sl *SlowLog) {
	heap.Push(h.h, sl)
	if h.h.Len() > h.limit {
		heap.Pop(h.h)
	}
}

func (h *slowLogsHeap) Slice() []*SlowLog {
	if h.h.Len() == 0 {
		return nil
	}
	rs := make([]*SlowLog, h.h.Len())
	for n := len(rs) - 1; n >= 0; n-- {
		rs[n] = heap.Pop(h.h).(*SlowLog)
	}
	return rs
}

var (
	_ heap.Interface = &slowLogsOrderByTimestampAscHeap{}
	_ heap.Interface = &slowLogsOrderByTimestampDescHeap{}
	_ heap.Interface = &slowLogsOrderByQueryTimeAscHeap{}
	_ heap.Interface = &slowLogsOrderByQueryTimeDescHeap{}
	_ heap.Interface = &slowLogsOrderByMemMaxAscHeap{}
	_ heap.Interface = &slowLogsOrderByMemMaxDescHeap{}
	_ heap.Interface = &slowLogsOrderByTotalKeysAscHeap{}
	_ heap.Interface = &slowLogsOrderByTotalKeysDescHeap{}
)

type slowLogsOrderByTimestampAscHeap []*SlowLog

func (s slowLogsOrderByTimestampAscHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByTimestampAscHeap) Less(i, j int) bool {
	return s[i].Time.Before(s[j].Time)
}

func (s slowLogsOrderByTimestampAscHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByTimestampAscHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByTimestampAscHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByTimestampDescHeap []*SlowLog

func (s slowLogsOrderByTimestampDescHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByTimestampDescHeap) Less(i, j int) bool {
	return s[i].Time.After(s[j].Time)
}

func (s slowLogsOrderByTimestampDescHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByTimestampDescHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByTimestampDescHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByQueryTimeAscHeap []*SlowLog

func (s slowLogsOrderByQueryTimeAscHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByQueryTimeAscHeap) Less(i, j int) bool {
	return s[i].QueryTime < s[j].QueryTime
}

func (s slowLogsOrderByQueryTimeAscHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByQueryTimeAscHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByQueryTimeAscHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByQueryTimeDescHeap []*SlowLog

func (s slowLogsOrderByQueryTimeDescHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByQueryTimeDescHeap) Less(i, j int) bool {
	return s[i].QueryTime > s[j].QueryTime
}

func (s slowLogsOrderByQueryTimeDescHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByQueryTimeDescHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByQueryTimeDescHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByMemMaxAscHeap []*SlowLog

func (s slowLogsOrderByMemMaxAscHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByMemMaxAscHeap) Less(i, j int) bool {
	return s[i].MemMax < s[j].MemMax
}

func (s slowLogsOrderByMemMaxAscHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByMemMaxAscHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByMemMaxAscHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByMemMaxDescHeap []*SlowLog

func (s slowLogsOrderByMemMaxDescHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByMemMaxDescHeap) Less(i, j int) bool {
	return s[i].MemMax > s[j].MemMax
}

func (s slowLogsOrderByMemMaxDescHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByMemMaxDescHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByMemMaxDescHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByTotalKeysAscHeap []*SlowLog

func (s slowLogsOrderByTotalKeysAscHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByTotalKeysAscHeap) Less(i, j int) bool {
	return s[i].TotalKeys < s[j].TotalKeys
}

func (s slowLogsOrderByTotalKeysAscHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByTotalKeysAscHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByTotalKeysAscHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByTotalKeysDescHeap []*SlowLog

func (s slowLogsOrderByTotalKeysDescHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByTotalKeysDescHeap) Less(i, j int) bool {
	return s[i].TotalKeys > s[j].TotalKeys
}

func (s slowLogsOrderByTotalKeysDescHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByTotalKeysDescHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByTotalKeysDescHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByProcessKeysAscHeap []*SlowLog

func (s slowLogsOrderByProcessKeysAscHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByProcessKeysAscHeap) Less(i, j int) bool {
	return s[i].ProcessKeys < s[j].ProcessKeys
}

func (s slowLogsOrderByProcessKeysAscHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByProcessKeysAscHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByProcessKeysAscHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}

type slowLogsOrderByProcessKeysDescHeap []*SlowLog

func (s slowLogsOrderByProcessKeysDescHeap) Len() int {
	return len(s)
}

func (s slowLogsOrderByProcessKeysDescHeap) Less(i, j int) bool {
	return s[i].ProcessKeys > s[j].ProcessKeys
}

func (s slowLogsOrderByProcessKeysDescHeap) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s *slowLogsOrderByProcessKeysDescHeap) Push(x any) {
	*s = append(*s, x.(*SlowLog))
}

func (s *slowLogsOrderByProcessKeysDescHeap) Pop() any {
	old := *s
	n := len(old)
	x := old[n-1]
	old[n-1] = nil
	*s = old[0 : n-1]
	return x
}
