package logger

import (
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// Logger wraps zap.Logger for structured logging
type Logger struct {
	*zap.Logger
}

// NewLogger creates a new logger instance
func NewLogger(service string) *Logger {
	config := zap.NewProductionConfig()
	config.EncoderConfig.TimeKey = "timestamp"
	config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	config.EncoderConfig.MessageKey = "message"
	config.EncoderConfig.LevelKey = "level"

	// Use JSON format by default, can be overridden via env
	logFormat := os.Getenv("CALYPSO_LOG_FORMAT")
	if logFormat == "text" {
		config.Encoding = "console"
		config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
	}

	// Set log level from environment
	logLevel := os.Getenv("CALYPSO_LOG_LEVEL")
	if logLevel != "" {
		var level zapcore.Level
		if err := level.UnmarshalText([]byte(logLevel)); err == nil {
			config.Level = zap.NewAtomicLevelAt(level)
		}
	}

	zapLogger, err := config.Build(
		zap.AddCaller(),
		zap.AddStacktrace(zapcore.ErrorLevel),
		zap.Fields(zap.String("service", service)),
	)
	if err != nil {
		panic(err)
	}

	return &Logger{zapLogger}
}

// WithFields adds structured fields to the logger
func (l *Logger) WithFields(fields ...zap.Field) *Logger {
	return &Logger{l.Logger.With(fields...)}
}

// Info logs an info message with optional fields
func (l *Logger) Info(msg string, fields ...interface{}) {
	zapFields := toZapFields(fields...)
	l.Logger.Info(msg, zapFields...)
}

// Error logs an error message with optional fields
func (l *Logger) Error(msg string, fields ...interface{}) {
	zapFields := toZapFields(fields...)
	l.Logger.Error(msg, zapFields...)
}

// Warn logs a warning message with optional fields
func (l *Logger) Warn(msg string, fields ...interface{}) {
	zapFields := toZapFields(fields...)
	l.Logger.Warn(msg, zapFields...)
}

// Debug logs a debug message with optional fields
func (l *Logger) Debug(msg string, fields ...interface{}) {
	zapFields := toZapFields(fields...)
	l.Logger.Debug(msg, zapFields...)
}

// Fatal logs a fatal message and exits
func (l *Logger) Fatal(msg string, fields ...interface{}) {
	zapFields := toZapFields(fields...)
	l.Logger.Fatal(msg, zapFields...)
}

// toZapFields converts key-value pairs to zap fields
func toZapFields(fields ...interface{}) []zap.Field {
	zapFields := make([]zap.Field, 0, len(fields)/2)
	for i := 0; i < len(fields)-1; i += 2 {
		key, ok := fields[i].(string)
		if !ok {
			continue
		}
		zapFields = append(zapFields, zap.Any(key, fields[i+1]))
	}
	return zapFields
}

