package tx

import (
	"fmt"
	"time"

	"code.justin.tv/release/trace/analysis/callgraph"
	"code.justin.tv/release/trace/api"
	"code.justin.tv/release/trace/pbmsg"
)

// Transaction represents a collection of calls with a common
// TransactionID.
type Transaction struct {
	Root callgraph.CallNode
	ID   TransactionID

	Tx *api.Transaction
}

// NewTransaction produces an empty transaction
func NewTransaction(id TransactionID) *Transaction {
	return &Transaction{
		Root: callgraph.NewCallGraph(),
		ID:   id,
	}
}

// Add adds an event to the Transaction
func (tx *Transaction) Add(event *pbmsg.Event) {
	tx.Root.Add(event)
}

// StringID returns the string representation of the transaction's ID.
func (tx *Transaction) StringID() string {
	return tx.ID.String()
}

func (tx *Transaction) CompactDescr() string {
	ms := float64(tx.RootDuration()) / float64(time.Millisecond)
	return fmt.Sprintf("dur:%.2fms  depth:%d  size:%d",
		ms, tx.Depth(), tx.Size(),
	)
}

// RootService gets the Server name at the root of the
// transaction. returns "" if the root's service is not known.
func (tx *Transaction) RootService() string {
	return tx.Root.Label(callgraph.Server)
}

// RootDuration returns the time that the root call took according to
// the client. If the client did not send data, then the time
// according to the server of the root call is returned.
func (tx *Transaction) RootDuration() time.Duration {
	var d int64
	if d = tx.Root.IntValue(callgraph.ClientNanos); d != 0 {
		return time.Duration(d)
	}
	if d = tx.Root.IntValue(callgraph.ServerNanos); d != 0 {
		return time.Duration(d)
	}
	return 0
}

// Size returns the number of spans in the transaction.
func (tx *Transaction) Size() int {
	return callgraph.TreeSize(tx.Root)
}

// Depth returns the maximum path depth of the transaction.
func (tx *Transaction) Depth() int {
	return callgraph.Height(tx.Root)
}
