package api

import (
	"fmt"

	"github.com/go-delve/delve/pkg/goversion"
)

var waitReasonStrings1dot18 = []string{
	"",
	"GC assist marking",
	"IO wait",
	"chan receive (nil chan)",
	"chan send (nil chan)",
	"dumping heap",
	"garbage collection",
	"garbage collection scan",
	"panicwait",
	"select",
	"select (no cases)",
	"GC assist wait",
	"GC sweep wait",
	"GC scavenge wait",
	"chan receive",
	"chan send",
	"finalizer wait",
	"force gc (idle)",
	"semacquire",
	"sleep",
	"sync.Cond.Wait",
	"timer goroutine (idle)",
	"trace reader (blocked)",
	"wait for GC cycle",
	"GC worker (idle)",
	"preempted",
	"debug call",
}

var waitReasonStrings1dot20 = []string{
	"",
	"GC assist marking",
	"IO wait",
	"chan receive (nil chan)",
	"chan send (nil chan)",
	"dumping heap",
	"garbage collection",
	"garbage collection scan",
	"panicwait",
	"select",
	"select (no cases)",
	"GC assist wait",
	"GC sweep wait",
	"GC scavenge wait",
	"chan receive",
	"chan send",
	"finalizer wait",
	"force gc (idle)",
	"semacquire",
	"sleep",
	"sync.Cond.Wait",
	"sync.Mutex.Lock",
	"sync.RWMutex.RLock",
	"sync.RWMutex.Lock",
	"trace reader (blocked)",
	"wait for GC cycle",
	"GC worker (idle)",
	"GC worker (active)",
	"preempted",
	"debug call",
	"GC mark termination",
	"stopping the world",
}

var waitReasonStrings1dot22 = []string{
	"",
	"GC assist marking",
	"IO wait",
	"chan receive (nil chan)",
	"chan send (nil chan)",
	"dumping heap",
	"garbage collection",
	"garbage collection scan",
	"panicwait",
	"select",
	"select (no cases)",
	"GC assist wait",
	"GC sweep wait",
	"GC scavenge wait",
	"chan receive",
	"chan send",
	"finalizer wait",
	"force gc (idle)",
	"semacquire",
	"sleep",
	"sync.Cond.Wait",
	"sync.Mutex.Lock",
	"sync.RWMutex.RLock",
	"sync.RWMutex.Lock",
	"trace reader (blocked)",
	"wait for GC cycle",
	"GC worker (idle)",
	"GC worker (active)",
	"preempted",
	"debug call",
	"GC mark termination",
	"stopping the world",
	"flushing proc caches",
	"trace goroutine status",
	"trace proc status",
	"page trace flush",
	"coroutine",
}

var waitReasonStrings1dot24 = []string{
	"",
	"GC assist marking",
	"IO wait",
	"chan receive (nil chan)",
	"chan send (nil chan)",
	"dumping heap",
	"garbage collection",
	"garbage collection scan",
	"panicwait",
	"select",
	"select (no cases)",
	"GC assist wait",
	"GC sweep wait",
	"GC scavenge wait",
	"chan receive",
	"chan send",
	"finalizer wait",
	"force gc (idle)",
	"semacquire",
	"sleep",
	"sync.Cond.Wait",
	"sync.Mutex.Lock",
	"sync.RWMutex.RLock",
	"sync.RWMutex.Lock",
	"sync.WaitGroup.Wait",
	"trace reader (blocked)",
	"wait for GC cycle",
	"GC worker (idle)",
	"GC worker (active)",
	"preempted",
	"debug call",
	"GC mark termination",
	"stopping the world",
	"flushing proc caches",
	"trace goroutine status",
	"trace proc status",
	"page trace flush",
	"coroutine",
	"GC weak to strong wait",
	"synctest.Run",
	"synctest.Wait",
	"chan receive (synctest)",
	"chan send (synctest)",
}

var waitReasonStrings1dot25 = []string{
	"",
	"GC assist marking",
	"IO wait",
	"chan receive (nil chan)",
	"chan send (nil chan)",
	"dumping heap",
	"garbage collection",
	"garbage collection scan",
	"panicwait",
	"select",
	"select (no cases)",
	"GC assist wait",
	"GC sweep wait",
	"GC scavenge wait",
	"chan receive",
	"chan send",
	"finalizer wait",
	"force gc (idle)",
	"GOMAXPROCS updater (idle)",
	"semacquire",
	"sleep",
	"sync.Cond.Wait",
	"sync.Mutex.Lock",
	"sync.RWMutex.RLock",
	"sync.RWMutex.Lock",
	"sync.WaitGroup.Wait",
	"trace reader (blocked)",
	"wait for GC cycle",
	"GC worker (idle)",
	"GC worker (active)",
	"preempted",
	"debug call",
	"GC mark termination",
	"stopping the world",
	"flushing proc caches",
	"trace goroutine status",
	"trace proc status",
	"page trace flush",
	"coroutine",
	"GC weak to strong wait",
	"synctest.Run",
	"synctest.Wait",
	"chan receive (durable)",
	"chan send (durable)",
	"select (durable)",
	"sync.WaitGroup.Wait (durable)",
	"cleanup wait",
}

var waitReasonStrings1dot26 = []string{
	"",
	"GC assist marking",
	"IO wait",
	"dumping heap",
	"garbage collection",
	"garbage collection scan",
	"panicwait",
	"GC assist wait",
	"GC sweep wait",
	"GC scavenge wait",
	"finalizer wait",
	"force gc (idle)",
	"GOMAXPROCS updater (idle)",
	"semacquire",
	"sleep",
	"chan receive (nil chan)",
	"chan send (nil chan)",
	"select (no cases)",
	"select",
	"chan receive",
	"chan send",
	"sync.Cond.Wait",
	"sync.Mutex.Lock",
	"sync.RWMutex.RLock",
	"sync.RWMutex.Lock",
	"sync.WaitGroup.Wait",
	"trace reader (blocked)",
	"wait for GC cycle",
	"GC worker (idle)",
	"GC worker (active)",
	"preempted",
	"debug call",
	"GC mark termination",
	"stopping the world",
	"flushing proc caches",
	"trace goroutine status",
	"trace proc status",
	"page trace flush",
	"coroutine",
	"GC weak to strong wait",
	"synctest.Run",
	"synctest.Wait",
	"chan receive (durable)",
	"chan send (durable)",
	"select (durable)",
	"sync.WaitGroup.Wait (durable)",
	"cleanup wait",
}

func WaitReasonString(goVersion *goversion.GoVersion, waitReason int64) string {
	var waitReasonStrings []string

	switch goVersion.Minor {
	case 18, 19:
		waitReasonStrings = waitReasonStrings1dot18
	case 20, 21:
		waitReasonStrings = waitReasonStrings1dot20
	case 22, 23:
		waitReasonStrings = waitReasonStrings1dot22
	case 24:
		waitReasonStrings = waitReasonStrings1dot24
	case 25:
		waitReasonStrings = waitReasonStrings1dot25
	case 26, 27:
		waitReasonStrings = waitReasonStrings1dot26
	}

	if goVersion.Major != 1 {
		waitReasonStrings = nil
	}

	if waitReasonStrings != nil && waitReason > 0 && waitReason < int64(len(waitReasonStrings)) {
		return waitReasonStrings[waitReason]
	} else {
		return fmt.Sprintf("unknown wait reason %d", waitReason)
	}
}
