package logger

import (
	"io"
	"os"
	"time"

	"github.com/rs/zerolog"
	"go.opentelemetry.io/otel/trace"

	"github.com/hatchet-dev/hatchet/pkg/analytics"
	"github.com/hatchet-dev/hatchet/pkg/config/shared"
)

type traceHook struct{}

func (h traceHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
	ctx := e.GetCtx()

	span := trace.SpanFromContext(ctx)
	if span.SpanContext().IsValid() {
		e.Str("trace_id", span.SpanContext().TraceID().String())
		e.Str("span_id", span.SpanContext().SpanID().String())
	}

	if id := analytics.TenantIDFromContext(ctx); id != nil {
		e.Str("tenant_id", id.String())
	}
	if id := analytics.OrganizationIDFromContext(ctx); id != nil {
		e.Str("organization_id", id.String())
	}
	if id := analytics.UserIDFromContext(ctx); id != nil {
		e.Str("user_id", id.String())
	}
}

func init() {
	zerolog.TimeFieldFormat = time.RFC3339Nano
}

func NewDefaultLogger(service string) zerolog.Logger {
	return NewStdErr(&shared.LoggerConfigFile{}, service)
}

func NewStdErr(cf *shared.LoggerConfigFile, service string) zerolog.Logger {
	lvl := zerolog.DebugLevel
	var err error

	if cf.Level != "" {
		lvl, err = zerolog.ParseLevel(cf.Level)

		if err != nil {
			panic(err)
		}
	}

	var out io.Writer = os.Stderr

	if cf.Format == "console" {
		out = zerolog.ConsoleWriter{
			Out:        os.Stderr,
			TimeFormat: "2006-01-02T15:04:05.999Z07:00",
		}
	}

	l := zerolog.New(out).Level(lvl)
	l = l.With().Timestamp().Logger()
	l = l.Hook(traceHook{})

	if service != "" {
		l = l.With().Str("service", service).Logger()
	}

	return l
}
