// Package logger provides a unified structured logger for all Cyrene services.
// It wraps Go's log/slog with opinionated defaults (JSON output, caller info,
// service name tagging) and printf-style convenience methods compatible with
// the standard log package for easy migration.
package logger

import (
	"fmt"
	"log/slog"
	"os"
)

// Logger wraps slog.Logger with printf-style convenience methods.
type Logger struct {
	inner *slog.Logger
}

// New creates a new Logger for the named service.
// By default it writes JSON to stderr at Info level with caller info.
func New(service string, opts ...Option) *Logger {
	cfg := config{
		level:   slog.LevelInfo,
		format:  FormatJSON,
		output:  os.Stderr,
		service: service,
	}
	for _, o := range opts {
		o(&cfg)
	}
	h := slog.NewJSONHandler(cfg.output, &slog.HandlerOptions{
		Level:     cfg.level,
		AddSource: true,
	})
	return &Logger{
		inner: slog.New(h).With(slog.String("svc", cfg.service)),
	}
}

// Slog returns the underlying slog.Logger for direct structured logging.
func (l *Logger) Slog() *slog.Logger { return l.inner }

// Debug logs a debug-level message (printf style).
func (l *Logger) Debug(format string, args ...any) {
	l.inner.Debug(fmt.Sprintf(format, args...))
}

// Info logs an info-level message (printf style).
func (l *Logger) Info(format string, args ...any) {
	l.inner.Info(fmt.Sprintf(format, args...))
}

// Warn logs a warn-level message (printf style).
func (l *Logger) Warn(format string, args ...any) {
	l.inner.Warn(fmt.Sprintf(format, args...))
}

// Error logs an error-level message (printf style).
func (l *Logger) Error(format string, args ...any) {
	l.inner.Error(fmt.Sprintf(format, args...))
}

// Fatal logs an error-level message and exits with code 1.
func (l *Logger) Fatal(format string, args ...any) {
	l.inner.Error(fmt.Sprintf(format, args...))
	os.Exit(1)
}

// Format controls log output format.
type Format int

const (
	FormatJSON Format = iota
	FormatText
)

type config struct {
	level   slog.Level
	format  Format
	output  *os.File
	service string
}

// Option configures a logger.
type Option func(*config)

// WithLevel sets the minimum log level.
func WithLevel(l slog.Level) Option {
	return func(c *config) { c.level = l }
}

// WithFormat sets the output format (JSON or Text).
func WithFormat(f Format) Option {
	return func(c *config) { c.format = f }
}

// WithOutput sets the output writer (default stderr).
func WithOutput(f *os.File) Option {
	return func(c *config) { c.output = f }
}

// WithDebug enables debug-level logging and text format (for development).
func WithDebug() Option {
	return func(c *config) {
		c.level = slog.LevelDebug
		c.format = FormatText
	}
}

// --- global default logger (drop-in replacement for log package) ---

var defaultLogger *Logger

// SetDefault sets the global default logger. Call once from main().
func SetDefault(l *Logger) { defaultLogger = l }

func get() *Logger {
	if defaultLogger == nil {
		defaultLogger = New("unknown")
	}
	return defaultLogger
}

// Printf logs at info level (drop-in for log.Printf).
func Printf(format string, args ...any) { get().Info(format, args...) }

// Println logs at info level (drop-in for log.Println).
func Println(args ...any) { get().Info(fmt.Sprint(args...)) }

// Fatalf logs at error level and exits (drop-in for log.Fatalf).
func Fatalf(format string, args ...any) { get().Fatal(format, args...) }
