package main

import (
	"errors"
	"os"
	"time"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

func main() {
	// Default global logger (JSON output)
	log.Info().Msg("Default JSON logger")

	// Pretty console output for development
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
	log.Info().Msg("Pretty console output")

	// Create a custom logger
	logger := zerolog.New(os.Stdout).With().Timestamp().Logger()
	logger.Info().Msg("Custom logger with timestamp")

	// Structured logging with fields
	logger.Info().
		Str("user_id", "usr_123").
		Str("email", "alice@example.com").
		Int("login_count", 42).
		Msg("User logged in")

	// All log levels
	logger.Trace().Msg("Trace message")
	logger.Debug().Msg("Debug message")
	logger.Info().Msg("Info message")
	logger.Warn().Msg("Warning message")
	logger.Error().Msg("Error message")
	// logger.Fatal().Msg("Fatal") // calls os.Exit(1)
	// logger.Panic().Msg("Panic") // panics

	// Error logging with error field
	err := errors.New("database connection failed")
	logger.Error().
		Err(err).
		Str("host", "db.example.com").
		Int("retries", 3).
		Msg("Failed to connect")

	// Stack trace on errors
	logger.Error().
		Stack().
		Err(err).
		Msg("Error with stack trace")

	// Duration and time fields
	start := time.Now()
	time.Sleep(10 * time.Millisecond)
	logger.Info().
		Dur("elapsed", time.Since(start)).
		Time("started_at", start).
		Msg("Operation completed")

	// Child logger with preset fields
	requestLogger := logger.With().
		Str("request_id", "req_abc123").
		Str("method", "GET").
		Str("path", "/api/users").
		Logger()

	requestLogger.Info().Msg("Request started")
	requestLogger.Info().Int("status", 200).Msg("Request completed")

	// Conditional logging
	logger.Info().
		Str("user", "alice").
		Bool("premium", true).
		Msg("User action")

	// Array and object fields
	logger.Info().
		Strs("tags", []string{"api", "v2", "public"}).
		Ints("scores", []int{98, 85, 92}).
		Msg("Array fields")

	// Nested object
	logger.Info().
		Dict("user",
			zerolog.Dict().
				Str("id", "usr_123").
				Str("name", "Alice").
				Int("age", 30),
		).
		Msg("Nested object")

	// Set global log level
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
	logger.Debug().Msg("This won't be logged")
	logger.Info().Msg("This will be logged")

	// Sampling for high-volume logs
	sampled := logger.Sample(&zerolog.BasicSampler{N: 10})
	for i := 0; i < 100; i++ {
		sampled.Info().Int("i", i).Msg("Sampled log")
	}

	// Hook for custom processing
	hooked := logger.Hook(zerolog.HookFunc(func(e *zerolog.Event, level zerolog.Level, msg string) {
		e.Str("hook", "added_by_hook")
	}))
	hooked.Info().Msg("Message with hook")

	// Context with default fields for all logs
	ctx := logger.With().
		Str("service", "api-gateway").
		Str("version", "1.2.3").
		Logger()
	ctx.Info().Msg("Service started")
}
