package adverr

import (
	"runtime"
	"strconv"
	"strings"
)

// CallTrace represents a call stack trace similar to Java's stack trace
type CallTrace struct {
	frames *runtime.Frames
	more   bool
}

// Trace returns a new CallTrace starting from this call
// Use skip to skip the first entries in the trace
func Trace(skip int) *CallTrace {
	if DisableTrace {
		return nil
	}

	pc := make([]uintptr, CallStackLength+1)
	n := runtime.Callers(skip+1, pc)
	pc = pc[:n]
	return &CallTrace{runtime.CallersFrames(pc), n == CallStackLength+1}
}

func (ct *CallTrace) String() string {
	if ct == nil {
		return ""
	}

	b := new(strings.Builder)

	for frame, ok := ct.frames.Next(); ok; frame, ok = ct.frames.Next() {
		b.WriteString("\tat ")
		b.WriteString(frame.Function)
		b.WriteString(" (")
		b.WriteString(frame.File)
		b.WriteString(":")
		b.WriteString(strconv.Itoa(frame.Line))
		b.WriteString(")")
		b.WriteString("\n")
	}

	if ct.more {
		b.WriteString("\t ...\n")
	}

	return b.String()
}