package main

import (
	"fmt"
	"log/slog"
	"os"
	"path/filepath"
	"strconv"
)

// opsiDemo membekukan atribut time dan menormalisasi path sumber menjadi
// nama berkas saja, sehingga output contoh identik di setiap eksekusi dan
// tidak bergantung pada lokasi direktori proyek.
func opsiDemo() *slog.HandlerOptions {
	return &slog.HandlerOptions{
		Level:     slog.LevelInfo,
		AddSource: true,
		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
			if len(groups) > 0 {
				return a
			}
			switch a.Key {
			case slog.TimeKey:
				return slog.String(slog.TimeKey, "2026-01-15T08:00:00Z")
			case slog.SourceKey:
				if s, ok := a.Value.Any().(*slog.Source); ok {
					return slog.String(slog.SourceKey,
						filepath.Base(s.File)+":"+strconv.Itoa(s.Line))
				}
			}
			return a
		},
	}
}

// Kredensial mengimplementasikan slog.LogValuer: handler memanggil LogValue
// saat mencetak, sehingga sandi selalu tersamarkan di log.
type Kredensial struct {
	Pengguna string
	Sandi    string
}

func (k Kredensial) LogValue() slog.Value {
	return slog.GroupValue(
		slog.String("pengguna", k.Pengguna),
		slog.String("sandi", "***"),
	)
}

// Statistik membuktikan evaluasi lazy: LogValue hanya dipanggil ketika
// baris log benar-benar ditulis handler (level aktif).
type Statistik struct {
	hitung *int
}

func (s Statistik) LogValue() slog.Value {
	*s.hitung++
	return slog.IntValue(*s.hitung)
}

func main() {
	logger := slog.New(slog.NewTextHandler(os.Stdout, opsiDemo()))

	fmt.Println("--- atribut sumber pemanggilan (AddSource) ---")
	logger.Info("server siap", "port", 8080)
	logger.Warn("cache miss", "kunci", "pengguna:42")

	fmt.Println("--- LogValuer: kredensial tersamarkan ---")
	logger.Info("login berhasil", "kredensial", Kredensial{Pengguna: "budi", Sandi: "rahasia-123"})

	fmt.Println("--- evaluasi lazy pada level Debug yang dinonaktifkan ---")
	eval := 0
	logger.Debug("mode diagnosa", "statistik", Statistik{hitung: &eval})
	logger.Info("mode normal", "statistik", Statistik{hitung: &eval})
	fmt.Println("LogValue dipanggil:", eval, "kali")

	fmt.Println("--- slog.SetDefault ---")
	slog.SetDefault(logger)
	slog.Info("dari logger default")
}
