package logger

import (
	"api-soap-facturacion/internal/config"
	"encoding/json"
	"fmt"
	"go.uber.org/zap"
	"go.uber.org/zap/buffer"
	"go.uber.org/zap/zapcore"
	lumberjack "gopkg.in/natefinch/lumberjack.v2"
	"os"
	"strings"
)

// Logger es una interfaz que define los métodos necesarios para el logging
type Logger interface {
	Debug(msg string, fields ...Field)
	Info(msg string, fields ...Field)
	Warn(msg string, fields ...Field)
	Error(msg string, fields ...Field)
	Fatal(msg string, fields ...Field)
	With(fields ...Field) Logger
}

// Field es un campo para agregar contexto a los logs
type Field struct {
	Key   string
	Value interface{}
}

// zapLogger implementa la interfaz Logger usando zap
type zapLogger struct {
	logger *zap.Logger
}

// CustomEncoder implementa la interfaz zapcore.Encoder
type CustomEncoder struct {
	zapcore.Encoder
	pool        buffer.Pool
	serviceName string
}

// NewCustomEncoder crea un nuevo encoder personalizado
func NewCustomEncoder(cfg zapcore.EncoderConfig, serviceName string) zapcore.Encoder {
	return &CustomEncoder{
		Encoder:     zapcore.NewJSONEncoder(cfg),
		pool:        buffer.NewPool(),
		serviceName: serviceName,
	}
}

// EncodeEntry implementa el formato personalizado
// EncodeEntry implementa el formato personalizado
func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
	line := e.pool.Get()

	// Agregar nivel (INFO:, WARN:, etc.)
	levelStr := entry.Level.CapitalString()
	line.AppendString(levelStr)
	line.AppendString(": ")

	// Agregar timestamp
	timestamp := entry.Time.Format("2006/01/02 15:04:05")
	line.AppendString(timestamp)
	line.AppendString(" ")

	// Agregar información del archivo/línea si está disponible
	if entry.Caller.Defined {
		// Convertir la ruta a formato Unix para manejar uniformemente las barras
		filePath := strings.ReplaceAll(entry.Caller.File, "\\", "/")

		// Opciones para encontrar la parte relevante del path
		possiblePrefixes := []string{
			"/cmd/",
			"/internal/",
			"/pkg/",
			"/api/",
			"/app/",
			"/src/",
		}

		// Buscar el prefijo más cercano al final del path
		shortPath := filePath
		for _, prefix := range possiblePrefixes {
			if idx := strings.LastIndex(filePath, prefix); idx != -1 {
				// Encontramos un prefijo estándar de Go
				shortPath = filePath[idx+1:] // +1 para quitar el slash inicial
				break
			}
		}

		// Si no se encontró ningún prefijo, usar el último componente del path
		if shortPath == filePath {
			parts := strings.Split(filePath, "/")
			if len(parts) > 0 {
				shortPath = parts[len(parts)-1]
			}
		}

		caller := fmt.Sprintf("%s:%d: ", shortPath, entry.Caller.Line)
		line.AppendString(caller)
	}

	// Agregar nombre del servicio entre corchetes
	line.AppendString("[")
	line.AppendString(e.serviceName)
	line.AppendString("] ")

	// Agregar mensaje
	line.AppendString(entry.Message)

	// Procesar campos adicionales
	if len(fields) > 0 {
		// Usar encoder JSON para serializar los campos
		encoder := zapcore.NewMapObjectEncoder()

		// Agregar cada campo al encoder, excepto "service"
		for _, field := range fields {
			if field.Key != "service" {
				field.AddTo(encoder)
			}
		}

		// Solo mostramos los campos si hay alguno después de filtrar
		if len(encoder.Fields) > 0 {
			line.AppendString(" ")
			fieldsJSON, err := json.Marshal(encoder.Fields)
			if err == nil {
				line.AppendString(string(fieldsJSON))
			}
		}
	}

	line.AppendString("\n")
	return line, nil
}

//func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
//	line := e.pool.Get()
//
//	// Agregar nivel (INFO:, WARN:, etc.)
//	levelStr := entry.Level.CapitalString()
//	line.AppendString(levelStr)
//	line.AppendString(": ")
//
//	// Agregar timestamp
//	timestamp := entry.Time.Format("2006/01/02 15:04:05")
//	line.AppendString(timestamp)
//	line.AppendString(" ")
//
//	// Agregar información del archivo/línea si está disponible
//	if entry.Caller.Defined {
//		// Obtener solo la parte relevante de la ruta (después del último "api-soap-facturacion")
//		filePath := entry.Caller.File
//		if idx := strings.LastIndex(filePath, "api-soap-facturacion"); idx != -1 {
//			// Si encontramos la cadena, tomamos lo que viene después más "api-soap-facturacion"
//			filePath = filePath[idx:]
//		} else {
//			// Si no encontramos la cadena, intentamos tomar solo el nombre del archivo
//			if idx := strings.LastIndex(filePath, "/"); idx != -1 {
//				filePath = filePath[idx+1:]
//			} else if idx := strings.LastIndex(filePath, "\\"); idx != -1 {
//				filePath = filePath[idx+1:]
//			}
//		}
//
//		caller := fmt.Sprintf("%s:%d: ", filePath, entry.Caller.Line)
//		line.AppendString(caller)
//	}
//	// Agregar nombre del servicio entre corchetes
//	line.AppendString("[")
//	line.AppendString(e.serviceName)
//	line.AppendString("] ")
//
//	// Agregar mensaje
//	line.AppendString(entry.Message)
//
//	// Procesar campos adicionales
//	if len(fields) > 0 {
//		// Usar encoder JSON para serializar los campos
//		encoder := zapcore.NewMapObjectEncoder()
//
//		// Agregar cada campo al encoder, excepto "service"
//		for _, field := range fields {
//			if field.Key != "service" {
//				field.AddTo(encoder)
//			}
//		}
//
//		// Solo mostramos los campos si hay alguno después de filtrar
//		if len(encoder.Fields) > 0 {
//			line.AppendString(" ")
//			fieldsJSON, err := json.Marshal(encoder.Fields)
//			if err == nil {
//				line.AppendString(string(fieldsJSON))
//			}
//		}
//	}
//
//	line.AppendString("\n")
//	return line, nil
//}

//func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
//	line := e.pool.Get()
//
//	// Agregar nivel (INFO:, WARN:, etc.)
//	levelStr := entry.Level.CapitalString()
//	line.AppendString(levelStr)
//	line.AppendString(": ")
//
//	// Agregar timestamp
//	timestamp := entry.Time.Format("2006/01/02 15:04:05")
//	line.AppendString(timestamp)
//	line.AppendString(" ")
//
//	// Agregar información del archivo/línea si está disponible
//	if entry.Caller.Defined {
//		caller := fmt.Sprintf("%s:%d: ", entry.Caller.File, entry.Caller.Line)
//		line.AppendString(caller)
//	}
//
//	// Agregar nombre del servicio entre corchetes
//	line.AppendString("[")
//	line.AppendString(e.serviceName)
//	line.AppendString("] ")
//
//	// Agregar mensaje
//	line.AppendString(entry.Message)
//
//	// Procesar campos adicionales
//	if len(fields) > 0 {
//		// Usar encoder JSON para serializar los campos
//		encoder := zapcore.NewMapObjectEncoder()
//
//		// Agregar cada campo al encoder, excepto "service"
//		for _, field := range fields {
//			if field.Key != "service" {
//				field.AddTo(encoder)
//			}
//		}
//
//		// Solo mostramos los campos si hay alguno después de filtrar
//		if len(encoder.Fields) > 0 {
//			line.AppendString(" ")
//			fieldsJSON, err := json.Marshal(encoder.Fields)
//			if err == nil {
//				line.AppendString(string(fieldsJSON))
//			}
//		}
//	}
//
//	line.AppendString("\n")
//	return line, nil
//}

// Clone implementa la interfaz Encoder
func (e *CustomEncoder) Clone() zapcore.Encoder {
	return &CustomEncoder{
		Encoder:     e.Encoder.Clone(),
		pool:        e.pool,
		serviceName: e.serviceName,
	}
}

// NewLogger crea una nueva instancia de Logger
func NewLogger(cfg *config.Config) Logger {
	// Configurar nivel de log
	var level zapcore.Level
	switch cfg.App.LogLevel {
	case "debug":
		level = zapcore.DebugLevel
	case "info":
		level = zapcore.InfoLevel
	case "warn":
		level = zapcore.WarnLevel
	case "error":
		level = zapcore.ErrorLevel
	default:
		level = zapcore.InfoLevel
	}

	// Configuración básica para el encoder
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	// Crear el encoder personalizado
	customEncoder := NewCustomEncoder(encoderConfig, cfg.App.Name)

	// Configurar el output
	var core zapcore.Core
	if cfg.App.LogFilePath != "" {
		// Si se usa archivo con lumberjack
		logWriter := &lumberjack.Logger{
			Filename:   cfg.App.LogFilePath,
			MaxSize:    cfg.App.LogMaxSize,
			MaxBackups: cfg.App.LogMaxBackups,
			MaxAge:     cfg.App.LogMaxAge,
			Compress:   cfg.App.LogCompress,
		}

		core = zapcore.NewCore(
			customEncoder,
			zapcore.AddSync(logWriter),
			level,
		)
	} else {
		// Solo usar stdout
		core = zapcore.NewCore(
			customEncoder,
			zapcore.AddSync(os.Stdout),
			level,
		)
	}

	// Habilitar el caller para mostrar información del archivo y línea
	zapLog := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))

	// Ya no agregamos el nombre del servicio como campo, ya que lo incluimos en el formato
	// zapLog = zapLog.With(zap.String("service", cfg.App.Name))

	return &zapLogger{logger: zapLog}
}

// NewField crea un campo para agregar a los logs
func NewField(key string, value interface{}) Field {
	return Field{Key: key, Value: value}
}

// convertFields convierte nuestros campos a campos de zap
func (l *zapLogger) convertFields(fields []Field) []zap.Field {
	zapFields := make([]zap.Field, len(fields))
	for i, field := range fields {
		zapFields[i] = zap.Any(field.Key, field.Value)
	}
	return zapFields
}

// Debug registra un mensaje con nivel Debug
func (l *zapLogger) Debug(msg string, fields ...Field) {
	l.logger.Debug(msg, l.convertFields(fields)...)
}

// Info registra un mensaje con nivel Info
func (l *zapLogger) Info(msg string, fields ...Field) {
	l.logger.Info(msg, l.convertFields(fields)...)
}

// Warn registra un mensaje con nivel Warn
func (l *zapLogger) Warn(msg string, fields ...Field) {
	l.logger.Warn(msg, l.convertFields(fields)...)
}

// Error registra un mensaje con nivel Error
func (l *zapLogger) Error(msg string, fields ...Field) {
	l.logger.Error(msg, l.convertFields(fields)...)
}

// Fatal registra un mensaje con nivel Fatal
func (l *zapLogger) Fatal(msg string, fields ...Field) {
	l.logger.Fatal(msg, l.convertFields(fields)...)
}

// With retorna un nuevo logger con campos adicionales
func (l *zapLogger) With(fields ...Field) Logger {
	return &zapLogger{
		logger: l.logger.With(l.convertFields(fields)...),
	}
}

//package logger
//
//import (
//	"api-soap-facturacion/internal/config"
//	"encoding/json"
//	"fmt"
//	"go.uber.org/zap"
//	"go.uber.org/zap/zapcore"
//	lumberjack "gopkg.in/natefinch/lumberjack.v2" // Usa este alias
//	"os"
//)
//
//// Logger es una interfaz que define los métodos necesarios para el logging
//type Logger interface {
//	Debug(msg string, fields ...Field)
//	Info(msg string, fields ...Field)
//	Warn(msg string, fields ...Field)
//	Error(msg string, fields ...Field)
//	Fatal(msg string, fields ...Field)
//	With(fields ...Field) Logger
//}
//
//// Field es un campo para agregar contexto a los logs
//type Field struct {
//	Key   string
//	Value interface{}
//}
//
//// zapLogger implementa la interfaz Logger usando zap
//type zapLogger struct {
//	logger *zap.Logger
//}
//
//// CustomEncoder implementa la interfaz zapcore.Encoder
//type CustomEncoder struct {
//	zapcore.Encoder
//	pool        buffer.Pool
//	serviceName string
//}
//
//// NewCustomEncoder crea un nuevo encoder personalizado
//func NewCustomEncoder(cfg zapcore.EncoderConfig, serviceName string) zapcore.Encoder {
//	return &CustomEncoder{
//		Encoder:     zapcore.NewJSONEncoder(cfg),
//		pool:        buffer.NewPool(),
//		serviceName: serviceName,
//	}
//}
//
//// EncodeEntry implementa el formato personalizado
//func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
//	line := e.pool.Get()
//
//	// Agregar nivel (INFO:, WARN:, etc.)
//	levelStr := entry.Level.CapitalString()
//	line.AppendString(levelStr)
//	line.AppendString(": ")
//
//	// Agregar timestamp
//	timestamp := entry.Time.Format("2006/01/02 15:04:05")
//	line.AppendString(timestamp)
//	line.AppendString(" ")
//
//	// Agregar información del archivo/línea si está disponible
//	if entry.Caller.Defined {
//		caller := fmt.Sprintf("%s:%d: ", entry.Caller.File, entry.Caller.Line)
//		line.AppendString(caller)
//	}
//
//	// Agregar nombre del servicio entre corchetes
//	line.AppendString("[")
//	line.AppendString(e.serviceName)
//	line.AppendString("] ")
//
//	// Agregar mensaje
//	line.AppendString(entry.Message)
//
//	// Procesar campos adicionales
//	if len(fields) > 0 {
//		line.AppendString(" ")
//		fieldsMap := make(map[string]interface{})
//		for _, field := range fields {
//			if field.Key != "service" {
//				field.AddTo(fieldsMap)
//			}
//		}
//
//		if len(fieldsMap) > 0 {
//			fieldJSON, err := json.Marshal(fieldsMap)
//			if err == nil {
//				line.AppendString(string(fieldJSON))
//			}
//		}
//	}
//
//	line.AppendString("\n")
//	return line, nil
//}
//
//// Clone implementa la interfaz Encoder
//func (e *CustomEncoder) Clone() zapcore.Encoder {
//	return &CustomEncoder{
//		Encoder:     e.Encoder.Clone(),
//		pool:        e.pool,
//		serviceName: e.serviceName,
//	}
//}
//
//// NewLogger crea una nueva instancia de Logger tipo json
////func NewLogger(cfg *config.Config) Logger {
////	// Configurar nivel de log
////	var level zapcore.Level
////	switch cfg.App.LogLevel {
////	case "debug":
////		level = zapcore.DebugLevel
////	case "info":
////		level = zapcore.InfoLevel
////	case "warn":
////		level = zapcore.WarnLevel
////	case "error":
////		level = zapcore.ErrorLevel
////	default:
////		level = zapcore.InfoLevel
////	}
////
////	// Configurar encoderConfig
////	encoderConfig := zapcore.EncoderConfig{
////		TimeKey:        "time",
////		LevelKey:       "level",
////		NameKey:        "logger",
////		CallerKey:      "caller",
////		MessageKey:     "msg",
////		StacktraceKey:  "stacktrace",
////		LineEnding:     zapcore.DefaultLineEnding,
////		EncodeLevel:    zapcore.LowercaseLevelEncoder,
////		EncodeTime:     zapcore.ISO8601TimeEncoder,
////		EncodeDuration: zapcore.SecondsDurationEncoder,
////		EncodeCaller:   zapcore.ShortCallerEncoder,
////	}
////
////	// Crear escritores
////	var cores []zapcore.Core
////
////	// Siempre escribir a stdout
////	cores = append(cores, zapcore.NewCore(
////		zapcore.NewJSONEncoder(encoderConfig),
////		zapcore.AddSync(os.Stdout),
////		level,
////	))
////
////	// Si se especificó una ruta de archivo de logs, configurar rotación
////	if cfg.App.LogFilePath != "" {
////		logWriter := &lumberjack.Logger{
////			Filename:   cfg.App.LogFilePath,
////			MaxSize:    cfg.App.LogMaxSize,
////			MaxBackups: cfg.App.LogMaxBackups,
////			MaxAge:     cfg.App.LogMaxAge,
////			Compress:   cfg.App.LogCompress,
////		}
////
////		cores = append(cores, zapcore.NewCore(
////			zapcore.NewJSONEncoder(encoderConfig),
////			zapcore.AddSync(logWriter),
////			level,
////		))
////	}
////
////	// Combinar cores
////	core := zapcore.NewTee(cores...)
////
////	// Crear logger
////	zapLog := zap.New(core)
////	zapLog = zapLog.With(zap.String("service", cfg.App.Name))
////
////	return &zapLogger{logger: zapLog}
////}
//
//// fomato de texto mas flexible
//// NewLogger crea una nueva instancia de Logger
////func NewLogger(cfg *config.Config) Logger {
////	// Configurar nivel de log
////	var level zapcore.Level
////	switch cfg.App.LogLevel {
////	case "debug":
////		level = zapcore.DebugLevel
////	case "info":
////		level = zapcore.InfoLevel
////	case "warn":
////		level = zapcore.WarnLevel
////	case "error":
////		level = zapcore.ErrorLevel
////	default:
////		level = zapcore.InfoLevel
////	}
////
////	// Configurar encoderConfig para un formato más legible
////	encoderConfig := zapcore.EncoderConfig{
////		TimeKey:        "time",
////		LevelKey:       "level",
////		NameKey:        "logger",
////		CallerKey:      "caller",
////		FunctionKey:    zapcore.OmitKey,
////		MessageKey:     "msg",
////		StacktraceKey:  "stacktrace",
////		LineEnding:     zapcore.DefaultLineEnding,
////		EncodeLevel:    zapcore.CapitalLevelEncoder,                        // INFO en lugar de info
////		EncodeTime:     zapcore.TimeEncoderOfLayout("2006/01/02 15:04:05"), // Formato como 2025/05/15 00:13:07
////		EncodeDuration: zapcore.SecondsDurationEncoder,
////		EncodeCaller:   zapcore.ShortCallerEncoder,
////	}
////
////	// Crear un formato personalizado
////	consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
////
////	// Configurar el output final
////	var core zapcore.Core
////	if cfg.App.LogFilePath != "" && cfg.App.UseFileLogger {
////		// Si se usa archivo con lumberjack
////		logWriter := &lumberjack.Logger{
////			Filename:   cfg.App.LogFilePath,
////			MaxSize:    cfg.App.LogMaxSize,
////			MaxBackups: cfg.App.LogMaxBackups,
////			MaxAge:     cfg.App.LogMaxAge,
////			Compress:   cfg.App.LogCompress,
////		}
////
////		core = zapcore.NewCore(
////			consoleEncoder,
////			zapcore.AddSync(logWriter),
////			level,
////		)
////	} else {
////		// Solo usar stdout
////		core = zapcore.NewCore(
////			consoleEncoder,
////			zapcore.AddSync(os.Stdout),
////			level,
////		)
////	}
////
////	// Habilitar el caller para mostrar información del archivo y línea
////	zapLog := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
////
////	// Agregar nombre del servicio como prefijo constante
////	zapLog = zapLog.With(zap.String("service", cfg.App.Name))
////
////	return &zapLogger{logger: zapLog}
////}
//
//// NewLogger crea una nueva instancia de Logger
//func NewLogger(cfg *config.Config) Logger {
//	// Configurar nivel de log
//	var level zapcore.Level
//	switch cfg.App.LogLevel {
//	case "debug":
//		level = zapcore.DebugLevel
//	case "info":
//		level = zapcore.InfoLevel
//	case "warn":
//		level = zapcore.WarnLevel
//	case "error":
//		level = zapcore.ErrorLevel
//	default:
//		level = zapcore.InfoLevel
//	}
//
//	// Configuración básica para el encoder
//	encoderConfig := zapcore.EncoderConfig{
//		TimeKey:        "time",
//		LevelKey:       "level",
//		NameKey:        "logger",
//		CallerKey:      "caller",
//		FunctionKey:    zapcore.OmitKey,
//		MessageKey:     "msg",
//		StacktraceKey:  "stacktrace",
//		LineEnding:     zapcore.DefaultLineEnding,
//		EncodeLevel:    zapcore.CapitalLevelEncoder,
//		EncodeTime:     zapcore.ISO8601TimeEncoder,
//		EncodeDuration: zapcore.SecondsDurationEncoder,
//		EncodeCaller:   zapcore.ShortCallerEncoder,
//	}
//
//	// Crear el encoder personalizado
//	customEncoder := NewCustomEncoder(encoderConfig, cfg.App.Name)
//
//	// Configurar el output
//	var core zapcore.Core
//	if cfg.App.LogFilePath != "" {
//		// Si se usa archivo con lumberjack
//		logWriter := &lumberjack.Logger{
//			Filename:   cfg.App.LogFilePath,
//			MaxSize:    cfg.App.LogMaxSize,
//			MaxBackups: cfg.App.LogMaxBackups,
//			MaxAge:     cfg.App.LogMaxAge,
//			Compress:   cfg.App.LogCompress,
//		}
//
//		core = zapcore.NewCore(
//			customEncoder,
//			zapcore.AddSync(logWriter),
//			level,
//		)
//	} else {
//		// Solo usar stdout
//		core = zapcore.NewCore(
//			customEncoder,
//			zapcore.AddSync(os.Stdout),
//			level,
//		)
//	}
//
//	// Habilitar el caller para mostrar información del archivo y línea
//	zapLog := zap.New(core, zap.AddCaller())
//
//	// Ya no agregamos el nombre del servicio como campo, ya que lo incluimos en el formato
//	// zapLog = zapLog.With(zap.String("service", cfg.App.Name))
//
//	return &zapLogger{logger: zapLog}
//}
//
//// NewField crea un campo para agregar a los logs
//func NewField(key string, value interface{}) Field {
//	return Field{Key: key, Value: value}
//}
//
//// convertFields convierte nuestros campos a campos de zap
//func (l *zapLogger) convertFields(fields []Field) []zap.Field {
//	zapFields := make([]zap.Field, len(fields))
//	for i, field := range fields {
//		zapFields[i] = zap.Any(field.Key, field.Value)
//	}
//	return zapFields
//}
//
//// Debug registra un mensaje con nivel Debug
//func (l *zapLogger) Debug(msg string, fields ...Field) {
//	l.logger.Debug(msg, l.convertFields(fields)...)
//}
//
//// Info registra un mensaje con nivel Info
//func (l *zapLogger) Info(msg string, fields ...Field) {
//	l.logger.Info(msg, l.convertFields(fields)...)
//}
//
//// Warn registra un mensaje con nivel Warn
//func (l *zapLogger) Warn(msg string, fields ...Field) {
//	l.logger.Warn(msg, l.convertFields(fields)...)
//}
//
//// Error registra un mensaje con nivel Error
//func (l *zapLogger) Error(msg string, fields ...Field) {
//	l.logger.Error(msg, l.convertFields(fields)...)
//}
//
//// Fatal registra un mensaje con nivel Fatal
//func (l *zapLogger) Fatal(msg string, fields ...Field) {
//	l.logger.Fatal(msg, l.convertFields(fields)...)
//}
//
//// With retorna un nuevo logger con campos adicionales
////
////	func (l *zapLogger) With(fields ...Field) Logger {
////		return &zapLogger{
////			logger: l.logger.With(l.convertFields(fields)...),
////		}
////	}
//func (l *zapLogger) With(fields ...Field) Logger {
//	return &zapLogger{
//		logger: l.logger.With(l.convertFields(fields)...),
//	}
//}
//
////package logger
////
////import (
////	"api-soap-facturacion/internal/config"
////	"go.uber.org/zap"
////	"go.uber.org/zap/zapcore"
////)
////
////// Logger es una interfaz que define los métodos necesarios para el logging
////type Logger interface {
////	Debug(msg string, fields ...Field)
////	Info(msg string, fields ...Field)
////	Warn(msg string, fields ...Field)
////	Error(msg string, fields ...Field)
////	Fatal(msg string, fields ...Field)
////	With(fields ...Field) Logger
////}
////
////// Field es un campo para agregar contexto a los logs
////type Field struct {
////	Key   string
////	Value interface{}
////}
////
////// zapLogger implementa la interfaz Logger usando zap
////type zapLogger struct {
////	logger *zap.Logger
////}
////
////// NewLogger crea una nueva instancia de Logger
////func NewLogger(cfg *config.Config) Logger {
////	// Configurar nivel de log
////	var level zapcore.Level
////	switch cfg.App.LogLevel {
////	case "debug":
////		level = zapcore.DebugLevel
////	case "info":
////		level = zapcore.InfoLevel
////	case "warn":
////		level = zapcore.WarnLevel
////	case "error":
////		level = zapcore.ErrorLevel
////	default:
////		level = zapcore.InfoLevel
////	}
////
////	// Configuración de zap
////	zapConfig := zap.Config{
////		Level:            zap.NewAtomicLevelAt(level),
////		Development:      cfg.App.Environment == "development",
////		Encoding:         "json",
////		OutputPaths:      []string{"stdout"},
////		ErrorOutputPaths: []string{"stderr"},
////		EncoderConfig: zapcore.EncoderConfig{
////			TimeKey:        "time",
////			LevelKey:       "level",
////			NameKey:        "logger",
////			CallerKey:      "caller",
////			MessageKey:     "msg",
////			StacktraceKey:  "stacktrace",
////			LineEnding:     zapcore.DefaultLineEnding,
////			EncodeLevel:    zapcore.LowercaseLevelEncoder,
////			EncodeTime:     zapcore.ISO8601TimeEncoder,
////			EncodeDuration: zapcore.SecondsDurationEncoder,
////			EncodeCaller:   zapcore.ShortCallerEncoder,
////		},
////	}
////
////	// Agregar service name a todos los logs
////	logger, _ := zapConfig.Build()
////	logger = logger.With(zap.String("service", cfg.App.Name))
////
////	return &zapLogger{logger: logger}
////}
////
////// NewField crea un campo para agregar a los logs
////func NewField(key string, value interface{}) Field {
////	return Field{Key: key, Value: value}
////}
////
////// convertFields convierte nuestros campos a campos de zap
////func (l *zapLogger) convertFields(fields []Field) []zap.Field {
////	zapFields := make([]zap.Field, len(fields))
////	for i, field := range fields {
////		zapFields[i] = zap.Any(field.Key, field.Value)
////	}
////	return zapFields
////}
////
////// Debug registra un mensaje con nivel Debug
////func (l *zapLogger) Debug(msg string, fields ...Field) {
////	l.logger.Debug(msg, l.convertFields(fields)...)
////}
////
////// Info registra un mensaje con nivel Info
////func (l *zapLogger) Info(msg string, fields ...Field) {
////	l.logger.Info(msg, l.convertFields(fields)...)
////}
////
////// Warn registra un mensaje con nivel Warn
////func (l *zapLogger) Warn(msg string, fields ...Field) {
////	l.logger.Warn(msg, l.convertFields(fields)...)
////}
////
////// Error registra un mensaje con nivel Error
////func (l *zapLogger) Error(msg string, fields ...Field) {
////	l.logger.Error(msg, l.convertFields(fields)...)
////}
////
////// Fatal registra un mensaje con nivel Fatal
////func (l *zapLogger) Fatal(msg string, fields ...Field) {
////	l.logger.Fatal(msg, l.convertFields(fields)...)
////}
////
////// With retorna un nuevo logger con campos adicionales
////func (l *zapLogger) With(fields ...Field) Logger {
////	return &zapLogger{
////		logger: l.logger.With(l.convertFields(fields)...),
////	}
////}
