package helpers

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/evanw/esbuild/internal/logger"
)

type Timer struct {
	mutex sync.Mutex
	data  []timerData
}

type timerData struct {
	name  string
	time  time.Time
	isEnd bool
}

func (t *Timer) Begin(name string) {
	if t != nil {
		t.data = append(t.data, timerData{
			name: name,
			time: time.Now(),
		})
	}
}

func (t *Timer) End(name string) {
	if t != nil {
		t.data = append(t.data, timerData{
			name:  name,
			time:  time.Now(),
			isEnd: true,
		})
	}
}

func (t *Timer) Fork() *Timer {
	if t != nil {
		return &Timer{}
	}
	return nil
}

func (t *Timer) Join(other *Timer) {
	if t != nil && other != nil {
		t.mutex.Lock()
		defer t.mutex.Unlock()
		t.data = append(t.data, other.data...)
	}
}

func (t *Timer) Log(log logger.Log) {
	if t == nil {
		return
	}

	type pair struct {
		timerData
		index uint32
	}

	var notes []logger.MsgData
	var stack []pair
	indent := 0

	for _, item := range t.data {
		if !item.isEnd {
			top := pair{timerData: item, index: uint32(len(notes))}
			notes = append(notes, logger.MsgData{})
			stack = append(stack, top)
			indent++
		} else {
			indent--
			last := len(stack) - 1
			top := stack[last]
			stack = stack[:last]
			if item.name != top.name {
				panic("Internal error")
			}
			notes[top.index].Text = fmt.Sprintf("%s%s: %dms",
				strings.Repeat("  ", indent),
				top.name,
				item.time.Sub(top.time).Milliseconds())
		}
	}

	log.AddWithNotes(logger.Info, nil, logger.Range{},
		"Timing information (times may not nest hierarchically due to parallelism)", notes)
}
