// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !disable_events

package event

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

// Builder is a fluent builder for construction of new events.
type Builder struct {
	builderCommon
}

type builderCommon struct {
	ctx       context.Context
	data      *builder
	builderID uint64 // equals data.id if all is well
}

// preallocateLabels controls the space reserved for labels in a builder.
// Storing the first few labels directly in builders can avoid an allocation at
// all for the very common cases of simple events. The length needs to be large
// enough to cope with the majority of events but no so large as to cause undue
// stack pressure.
const preallocateLabels = 6

type builder struct {
	exporter    *Exporter
	Event       Event
	labels      [preallocateLabels]Label
	id          uint64
	parentStart time.Time
}

var builderPool = sync.Pool{New: func() interface{} { return &builder{} }}

// To initializes a builder from the values stored in a context.
func To(ctx context.Context) Builder {
	b := Builder{builderCommon{ctx: ctx}}
	b.data = newBuilder(ctx)
	if b.data != nil {
		b.builderID = b.data.id
	}
	return b
}

var builderID uint64 // atomic

func newBuilder(ctx context.Context) *builder {
	exporter, parent, parentStart := FromContext(ctx)
	if exporter == nil {
		return nil
	}
	b := allocBuilder()
	b.exporter = exporter
	b.parentStart = parentStart
	b.Event.Labels = b.labels[:0]
	b.Event.Parent = parent
	return b
}

func allocBuilder() *builder {
	b := builderPool.Get().(*builder)
	b.id = atomic.AddUint64(&builderID, 1)
	return b
}

// Clone returns a copy of this builder.
// The two copies can be independently delivered.
func (b Builder) Clone() Builder {
	return Builder{b.clone()}
}

func (b builderCommon) clone() builderCommon {
	if b.data == nil {
		return b
	}
	bb := allocBuilder()
	bbid := bb.id
	clone := builderCommon{ctx: b.ctx, data: bb, builderID: bb.id}
	*clone.data = *b.data
	clone.data.id = bbid
	if len(b.data.Event.Labels) == 0 || &b.data.labels[0] == &b.data.Event.Labels[0] {
		clone.data.Event.Labels = clone.data.labels[:len(b.data.Event.Labels)]
	} else {
		clone.data.Event.Labels = make([]Label, len(b.data.Event.Labels))
		copy(clone.data.Event.Labels, b.data.Event.Labels)
	}
	return clone
}

func (b Builder) Name(name string) Builder {
	if b.data != nil {
		b.data.Event.Name = name
	}
	return b
}

func (b Builder) Error(err error) Builder {
	if b.data != nil {
		b.data.Event.Error = err
	}
	return b
}

func (b builderCommon) addLabel(label Label) {
	if b.data != nil {
		checkValid(b.data, b.builderID)
	}
}

// With adds all the supplied labels to the event being constructed.
func (b Builder) With(labels ...Label) Builder {
	if b.data == nil || len(labels) == 0 {
		return b
	}
	checkValid(b.data, b.builderID)
	b.data.Event.Labels = append(b.data.Event.Labels, labels...)
	return b
}

func (b Builder) At(t time.Time) Builder {
	b.setAt(t)
	return b
}

func (b builderCommon) setAt(t time.Time) {
	if b.data != nil {
		checkValid(b.data, b.builderID)
		b.data.Event.At = t
	}
}

func (b Builder) Namespace(ns string) Builder {
	b.setNamespace(ns)
	return b
}

func (b builderCommon) setNamespace(ns string) {
	if b.data != nil {
		checkValid(b.data, b.builderID)
		b.data.Event.Namespace = ns
	}
}

// Log is a helper that calls Deliver with LogKind.
func (b Builder) Log(message string) {
	if b.data == nil {
		return
	}
	checkValid(b.data, b.builderID)
	if b.data.exporter.loggingEnabled() {
		b.data.exporter.mu.Lock()
		defer b.data.exporter.mu.Unlock()
		b.data.Event.Kind = LogKind
		b.data.Event.Message = message
		b.data.exporter.prepare(&b.data.Event)
		b.data.exporter.handler.Log(b.ctx, &b.data.Event)
	}
	b.done()
}

// Logf is a helper that uses fmt.Sprint to build the message and then
// calls Deliver with LogKind.
func (b Builder) Logf(template string, args ...interface{}) {
	if b.data == nil {
		return
	}
	checkValid(b.data, b.builderID)
	if b.data.exporter.loggingEnabled() {
		message := fmt.Sprintf(template, args...)
		// Duplicate code from Log so Exporter.deliver's invocation of runtime.Callers is correct.
		b.data.exporter.mu.Lock()
		defer b.data.exporter.mu.Unlock()
		b.data.Event.Kind = LogKind
		b.data.Event.Message = message
		b.data.exporter.prepare(&b.data.Event)
		b.data.exporter.handler.Log(b.ctx, &b.data.Event)
	}
	b.done()
}

func (b Builder) Metric(mv MetricValue) {
	if b.data == nil {
		return
	}
	checkValid(b.data, b.builderID)
	if b.data.exporter.metricsEnabled() {
		b.data.exporter.mu.Lock()
		defer b.data.exporter.mu.Unlock()
		if b.data.Event.Namespace == "" {
			b.data.Event.Namespace = mv.m.Descriptor().Namespace()
		}
		b.data.Event.Labels = append(b.data.Event.Labels, MetricVal.Of(mv.v), MetricKey.Of(mv.m))
		b.data.Event.Kind = MetricKind
		b.data.exporter.prepare(&b.data.Event)
		b.data.exporter.handler.Metric(b.ctx, &b.data.Event)
	}
	b.done()
}

// Annotate is a helper that calls Deliver with AnnotateKind.
func (b Builder) Annotate() {
	if b.data == nil {
		return
	}
	checkValid(b.data, b.builderID)
	if b.data.exporter.annotationsEnabled() {
		b.data.exporter.mu.Lock()
		defer b.data.exporter.mu.Unlock()
		b.data.exporter.prepare(&b.data.Event)
		b.data.exporter.handler.Annotate(b.ctx, &b.data.Event)
	}
	b.done()
}

// End is a helper that calls Deliver with EndKind.
func (b Builder) End() {
	if b.data == nil {
		return
	}
	checkValid(b.data, b.builderID)
	if b.data.exporter.tracingEnabled() {
		// If there is a DurationMetric label, emit a Metric event
		// with the time since Start was called.
		if v, ok := DurationMetric.Find(&b.data.Event); ok {
			m := v.(*Duration)
			b.Clone().Metric(m.Record(time.Since(b.data.parentStart)))
		}
		b.data.exporter.mu.Lock()
		defer b.data.exporter.mu.Unlock()
		b.data.Event.Kind = TraceKind
		b.data.exporter.prepare(&b.data.Event)
		b.data.exporter.handler.End(b.ctx, &b.data.Event)
	}
	b.done()
}

// Event returns a copy of the event currently being built.
func (b Builder) Event() *Event {
	checkValid(b.data, b.builderID)
	clone := b.data.Event
	if len(b.data.Event.Labels) > 0 {
		clone.Labels = make([]Label, len(b.data.Event.Labels))
		copy(clone.Labels, b.data.Event.Labels)
	}
	return &clone
}

func (b builderCommon) done() {
	*b.data = builder{}
	builderPool.Put(b.data)
}

// Start delivers a start event with the given name and labels.
// Its second return value is a Builder whose End method can be
// called to deliver the matching End event.
// (It is also fine to ignore the Builder.)
// All events created from the returned context will have this start event
// as their parent.
func (b Builder) Start(name string) (context.Context, Builder) {
	if b.data == nil {
		return b.ctx, Builder{}
	}
	checkValid(b.data, b.builderID)
	ctx := b.ctx
	var endBuilder Builder
	if b.data.exporter.tracingEnabled() {
		b.data.exporter.mu.Lock()
		defer b.data.exporter.mu.Unlock()
		b.data.exporter.lastEvent++
		traceID := b.data.exporter.lastEvent
		// create the end builder
		endBuilder = b.Clone()
		endBuilder.data.Event.Parent = traceID
		b.data.Event.Kind = TraceKind
		b.data.Event.TraceID = traceID
		b.data.exporter.prepare(&b.data.Event)
		// and now deliver the start event
		b.data.Event.Name = name
		now := time.Now()
		ctx = newContext(ctx, b.data.exporter, traceID, now)
		ctx = b.data.exporter.handler.Start(ctx, &b.data.Event)
		endBuilder.data.parentStart = now
		endBuilder.ctx = ctx
	}
	b.done()
	return ctx, endBuilder
}

func checkValid(b *builder, wantID uint64) {
	if b.exporter == nil || b.id != wantID {
		panic("Builder already delivered an event; missing call to Clone")
	}
}
