package otelx

import (
	"context"
	"log/slog"
	"os"
	"strings"

	"go.opentelemetry.io/otel/trace"
)

// traceHandler 包装一个 slog.Handler：每条带 ctx 的日志自动附上 trace_id / span_id，
// 从而「日志 ↔ 链路」互跳——在 Jaeger 看到一个 span 即可拿 trace_id 过滤日志，反之亦然。
// 只有用 *Context 方法（slog.InfoContext 等）且 ctx 里有活跃 span 时才会注入。
type traceHandler struct{ slog.Handler }

func (h traceHandler) Handle(ctx context.Context, r slog.Record) error {
	if sc := trace.SpanContextFromContext(ctx); sc.HasTraceID() {
		r.AddAttrs(slog.String("trace_id", sc.TraceID().String()))
		if sc.HasSpanID() {
			r.AddAttrs(slog.String("span_id", sc.SpanID().String()))
		}
	}
	return h.Handler.Handle(ctx, r)
}

func (h traceHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return traceHandler{h.Handler.WithAttrs(attrs)}
}
func (h traceHandler) WithGroup(name string) slog.Handler {
	return traceHandler{h.Handler.WithGroup(name)}
}

// SetupSlog 安装一个全局结构化日志器（JSON → stderr），自带 service 标签且链路感知，
// 并设为 slog 默认。此后任意 slog.InfoContext(ctx, ...) 都会带 trace_id（若 ctx 有 span）。
// 级别经 LOG_LEVEL 控制（debug/info/warn/error，默认 info）。
func SetupSlog(serviceName string) *slog.Logger {
	base := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: parseLevel(os.Getenv("LOG_LEVEL"))})
	logger := slog.New(traceHandler{base}).With("service", serviceName)
	slog.SetDefault(logger)
	return logger
}

func parseLevel(s string) slog.Level {
	switch strings.ToLower(s) {
	case "debug":
		return slog.LevelDebug
	case "warn", "warning":
		return slog.LevelWarn
	case "error":
		return slog.LevelError
	default:
		return slog.LevelInfo
	}
}

// TraceID 返回 ctx 当前 span 的 trace id（无则空）——供需要手动带 trace_id 的场景。
func TraceID(ctx context.Context) string {
	if sc := trace.SpanContextFromContext(ctx); sc.HasTraceID() {
		return sc.TraceID().String()
	}
	return ""
}
