// Copyright 2021 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

// ezap provides an implementation of zapcore.Core for events.
// To use globally:
//     zap.ReplaceGlobals(zap.New(NewCore(exporter)))
//
// If you call elogging.SetExporter, then you can pass nil
// for the exporter above and it will use the global one.
package ezap

import (
	"context"
	"fmt"
	"math"
	"reflect"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"golang.org/x/exp/event"
	"golang.org/x/exp/event/keys"
	"golang.org/x/exp/event/severity"
)

type core struct {
	builder event.Builder // never delivered, only cloned
}

var _ zapcore.Core = (*core)(nil)

func NewCore(ctx context.Context) zapcore.Core {
	return &core{
		builder: event.To(ctx),
	}
}

func (c *core) Enabled(level zapcore.Level) bool {
	return true
}

func (c *core) With(fields []zapcore.Field) zapcore.Core {
	c2 := *c
	c2.builder = c2.builder.Clone()
	addLabels(c2.builder, fields)
	return &c2
}

func (c *core) Write(e zapcore.Entry, fs []zapcore.Field) error {
	b := c.builder.Clone().
		At(e.Time).
		With(convertLevel(e.Level)).
		With(event.Name.Of(e.LoggerName))
	// TODO: add these additional labels more efficiently.
	if e.Stack != "" {
		b.With(keys.String("stack").Of(e.Stack))
	}
	if e.Caller.Defined {
		b.With(keys.String("caller").Of(e.Caller.String()))
	}
	addLabels(b, fs)
	b.Log(e.Message)
	return nil
}

func (c *core) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
	return ce.AddCore(e, c)
}

func (c *core) Sync() error { return nil }

// addLabels creates a new []event.Label with the given labels followed by the
// labels constructed from fields.
func addLabels(b event.Builder, fields []zap.Field) {
	for i := 0; i < len(fields); i++ {
		b.With(newLabel(fields[i]))
	}
}

func newLabel(f zap.Field) event.Label {
	switch f.Type {
	case zapcore.ArrayMarshalerType, zapcore.ObjectMarshalerType, zapcore.BinaryType, zapcore.ByteStringType,
		zapcore.Complex128Type, zapcore.Complex64Type, zapcore.TimeFullType, zapcore.ReflectType,
		zapcore.ErrorType:
		return keys.Value(f.Key).Of(f.Interface)
	case zapcore.DurationType:
		// TODO: avoid this allocation?
		return keys.Value(f.Key).Of(time.Duration(f.Integer))
	case zapcore.Float64Type:
		return keys.Float64(f.Key).Of(math.Float64frombits(uint64(f.Integer)))
	case zapcore.Float32Type:
		return keys.Float32(f.Key).Of(math.Float32frombits(uint32(f.Integer)))
	case zapcore.BoolType:
		b := false
		if f.Integer != 0 {
			b = true
		}
		return keys.Bool(f.Key).Of(b)
	case zapcore.Int64Type:
		return keys.Int64(f.Key).Of(f.Integer)
	case zapcore.Int32Type:
		return keys.Int32(f.Key).Of(int32(f.Integer))

		//, zapcore.Int16Type, zapcore.Int8Type,
		// 		zapcore.Uint64Type, zapcore.Uint32Type, zapcore.Uint16Type, zapcore.Uint8Type, zapcore.UintptrType:
		//		return (f.Key).Of(uint64(f.Integer))
	case zapcore.StringType:
		return keys.String(f.Key).Of(f.String)
	case zapcore.TimeType:
		key := keys.Value(f.Key)
		t := time.Unix(0, f.Integer)
		if f.Interface != nil {
			t = t.In(f.Interface.(*time.Location))
		}
		return key.Of(t)
	case zapcore.StringerType:
		return keys.String(f.Key).Of(stringerToString(f.Interface))
	case zapcore.NamespaceType:
		// TODO: ???
		return event.Label{}
	case zapcore.SkipType:
		// TODO: avoid creating a label at all in this case.
		return event.Label{}
	default:
		panic(fmt.Sprintf("unknown field type: %v", f))
	}
}

// Adapter from encodeStringer in go.uber.org/zap/zapcore/field.go.
func stringerToString(stringer interface{}) (s string) {
	// Try to capture panics (from nil references or otherwise) when calling
	// the String() method, similar to https://golang.org/src/fmt/print.go#L540
	defer func() {
		if err := recover(); err != nil {
			// If it's a nil pointer, just say "<nil>". The likeliest causes are a
			// Stringer that fails to guard against nil or a nil pointer for a
			// value receiver, and in either case, "<nil>" is a nice result.
			if v := reflect.ValueOf(stringer); v.Kind() == reflect.Ptr && v.IsNil() {
				s = "<nil>"
				return
			}
			s = fmt.Sprintf("PANIC=%v", err)
		}
	}()

	return stringer.(fmt.Stringer).String()
}

func convertLevel(level zapcore.Level) event.Label {
	switch level {
	case zapcore.DebugLevel:
		return severity.Debug
	case zapcore.InfoLevel:
		return severity.Info
	case zapcore.WarnLevel:
		return severity.Warning
	case zapcore.ErrorLevel:
		return severity.Error
	case zapcore.DPanicLevel:
		return severity.Of(severity.FatalLevel - 1)
	case zapcore.PanicLevel:
		return severity.Of(severity.FatalLevel + 1)
	case zapcore.FatalLevel:
		return severity.Fatal
	default:
		return severity.Trace
	}
}
