package observability

import (
	"context"
	"testing"
	"time"

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

func TestInitTracer_Disabled(t *testing.T) {
	t.Parallel()

	cfg := Config{
		Enabled: false,
	}

	ctx := context.Background()
	tp, err := InitTracer(ctx, cfg)
	if err != nil {
		t.Fatalf("InitTracer failed: %v", err)
	}

	if tp == nil {
		t.Fatal("Expected tracer provider, got nil")
	}
}

func TestInitTracer_DevelopmentMode(t *testing.T) {
	t.Parallel()

	cfg := Config{
		Enabled:        true,
		ServiceName:    "test-service",
		ServiceVersion: "1.0.0",
		Environment:    "development",
	}

	ctx := context.Background()
	tp, err := InitTracer(ctx, cfg)
	if err != nil {
		t.Fatalf("InitTracer failed: %v", err)
	}

	if tp == nil {
		t.Fatal("Expected tracer provider, got nil")
	}

	// Verify it's not a no-op tracer
	if _, ok := tp.(*noop.TracerProvider); ok {
		t.Error("Expected real tracer provider in development mode")
	}

	// Clean up
	if err := ShutdownTracer(ctx, tp); err != nil {
		t.Logf("Failed to shutdown tracer: %v", err)
	}
}

func TestInitTracer_ProductionMode_WithOTLP(t *testing.T) {
	t.Parallel()

	cfg := Config{
		Enabled:        true,
		ServiceName:    "test-service",
		ServiceVersion: "1.0.0",
		Environment:    "production",
		OTLPEndpoint:   "http://localhost:4318",
	}

	ctx := context.Background()
	tp, err := InitTracer(ctx, cfg)
	if err != nil {
		// OTLP endpoint might not be available in tests, that's okay
		t.Skipf("Skipping test - OTLP endpoint not available: %v", err)
	}

	if tp == nil {
		t.Fatal("Expected tracer provider, got nil")
	}

	// Clean up
	if err := ShutdownTracer(ctx, tp); err != nil {
		t.Logf("Failed to shutdown tracer: %v", err)
	}
}

func TestInitTracer_ProductionMode_WithoutOTLP(t *testing.T) {
	t.Parallel()

	cfg := Config{
		Enabled:        true,
		ServiceName:    "test-service",
		ServiceVersion: "1.0.0",
		Environment:    "production",
		OTLPEndpoint:   "",
	}

	ctx := context.Background()
	tp, err := InitTracer(ctx, cfg)
	if err != nil {
		t.Fatalf("InitTracer failed: %v", err)
	}

	if tp == nil {
		t.Fatal("Expected tracer provider, got nil")
	}

	// Clean up
	if err := ShutdownTracer(ctx, tp); err != nil {
		t.Logf("Failed to shutdown tracer: %v", err)
	}
}

func TestShutdownTracer(t *testing.T) {
	t.Parallel()

	cfg := Config{
		Enabled:        true,
		ServiceName:    "test-service",
		ServiceVersion: "1.0.0",
		Environment:    "development",
	}

	ctx := context.Background()
	tp, err := InitTracer(ctx, cfg)
	if err != nil {
		t.Fatalf("InitTracer failed: %v", err)
	}

	shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := ShutdownTracer(shutdownCtx, tp); err != nil {
		t.Errorf("ShutdownTracer failed: %v", err)
	}
}

func TestShutdownTracer_NoopTracer(t *testing.T) {
	t.Parallel()

	tp := noop.NewTracerProvider()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// Should not fail for no-op tracer
	if err := ShutdownTracer(ctx, tp); err != nil {
		t.Errorf("ShutdownTracer should handle no-op tracer gracefully: %v", err)
	}
}

func TestInitTracer_InvalidResource(t *testing.T) {
	t.Parallel()

	// This test would require invalid resource configuration
	// Since resource.New doesn't have easy ways to fail, we'll skip this
	// In practice, resource.New should always succeed with valid inputs
	t.Skip("Skipping - resource.New doesn't easily fail with test inputs")
}

func TestTracerProvider_ImplementsInterface(t *testing.T) {
	t.Parallel()

	cfg := Config{
		Enabled:        true,
		ServiceName:    "test-service",
		ServiceVersion: "1.0.0",
		Environment:    "development",
	}

	ctx := context.Background()
	tp, err := InitTracer(ctx, cfg)
	if err != nil {
		t.Skipf("Skipping test - tracer init failed: %v", err)
	}

	// Verify it implements the interface (compile-time check)
	// If tp doesn't implement trace.TracerProvider, this won't compile
	_ = tp

	// Clean up
	if err := ShutdownTracer(ctx, tp); err != nil {
		t.Logf("Failed to shutdown tracer: %v", err)
	}
}
