package logger

import (
	"os"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
)

var Logger *logrus.Logger

// InitLogger initializes the logger
func InitLogger() {
	Logger = logrus.New()

	// Set log level based on environment
	logLevel := os.Getenv("LOG_LEVEL")
	if logLevel == "" {
		logLevel = "info"
	}

	level, err := logrus.ParseLevel(logLevel)
	if err != nil {
		level = logrus.InfoLevel
	}

	Logger.SetLevel(level)

	// Set formatter
	Logger.SetFormatter(&logrus.JSONFormatter{
		TimestampFormat: time.RFC3339,
	})

	// Set output to stdout by default
	Logger.SetOutput(os.Stdout)
}

// GetLogger returns the logger instance
func GetLogger() *logrus.Logger {
	if Logger == nil {
		InitLogger()
	}
	return Logger
}

// GinLogger returns a gin middleware for logging
func GinLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		// Start timer
		start := time.Now()
		path := c.Request.URL.Path
		raw := c.Request.URL.RawQuery

		// Process request
		c.Next()

		// Stop timer
		end := time.Now()
		latency := end.Sub(start)

		// Get client IP
		clientIP := c.ClientIP()

		// Get method
		method := c.Request.Method

		// Get status code
		statusCode := c.Writer.Status()

		// Get error message if any
		var errorMessage string
		if len(c.Errors) > 0 {
			errorMessage = c.Errors.String()
		}

		// Get body size
		bodySize := c.Writer.Size()

		// Get request ID if available
		requestID := c.GetHeader("X-Request-ID")
		if requestID == "" {
			requestID = c.GetString("requestID")
		}

		// Get user ID if available
		userID := c.GetString("userID")

		// Log the request
		entry := GetLogger().WithFields(logrus.Fields{
			"request_id":    requestID,
			"user_id":       userID,
			"client_ip":     clientIP,
			"method":        method,
			"path":          path,
			"query":         raw,
			"status_code":   statusCode,
			"body_size":     bodySize,
			"latency":       latency,
			"latency_human": latency.String(),
			"error_message": errorMessage,
		})

		if statusCode >= 500 {
			entry.Error()
		} else if statusCode >= 400 {
			entry.Warn()
		} else {
			entry.Info()
		}
	}
}

// WithRequestID adds a request ID to the logger
func WithRequestID(requestID string) *logrus.Entry {
	return GetLogger().WithField("request_id", requestID)
}

// WithUserID adds a user ID to the logger
func WithUserID(userID string) *logrus.Entry {
	return GetLogger().WithField("user_id", userID)
}

// WithError adds an error to the logger
func WithError(err error) *logrus.Entry {
	return GetLogger().WithError(err)
}

// WithField adds a custom field to the logger
func WithField(key string, value interface{}) *logrus.Entry {
	return GetLogger().WithField(key, value)
}

// WithFields adds multiple custom fields to the logger
func WithFields(fields logrus.Fields) *logrus.Entry {
	return GetLogger().WithFields(fields)
}

// Info logs an info message
func Info(args ...interface{}) {
	GetLogger().Info(args...)
}

// Infof logs a formatted info message
func Infof(format string, args ...interface{}) {
	GetLogger().Infof(format, args...)
}

// Warn logs a warning message
func Warn(args ...interface{}) {
	GetLogger().Warn(args...)
}

// Warnf logs a formatted warning message
func Warnf(format string, args ...interface{}) {
	GetLogger().Warnf(format, args...)
}

// Error logs an error message
func Error(args ...interface{}) {
	GetLogger().Error(args...)
}

// Errorf logs a formatted error message
func Errorf(format string, args ...interface{}) {
	GetLogger().Errorf(format, args...)
}

// Fatal logs a fatal message and exits
func Fatal(args ...interface{}) {
	GetLogger().Fatal(args...)
}

// Fatalf logs a formatted fatal message and exits
func Fatalf(format string, args ...interface{}) {
	GetLogger().Fatalf(format, args...)
}

// Debug logs a debug message
func Debug(args ...interface{}) {
	GetLogger().Debug(args...)
}

// Debugf logs a formatted debug message
func Debugf(format string, args ...interface{}) {
	GetLogger().Debugf(format, args...)
}

// Panic logs a panic message and panics
func Panic(args ...interface{}) {
	GetLogger().Panic(args...)
}

// Panicf logs a formatted panic message and panics
func Panicf(format string, args ...interface{}) {
	GetLogger().Panicf(format, args...)
}

// LogDatabaseOperation logs a database operation
func LogDatabaseOperation(operation string, table string, duration time.Duration, err error) {
	entry := GetLogger().WithFields(logrus.Fields{
		"operation": operation,
		"table":     table,
		"duration":  duration,
	})

	if err != nil {
		entry.WithError(err).Error("Database operation failed")
	} else {
		entry.Info("Database operation completed")
	}
}

// LogAIInteraction logs an AI interaction
func LogAIInteraction(model string, promptLength int, responseLength int, duration time.Duration, success bool, err error) {
	entry := GetLogger().WithFields(logrus.Fields{
		"ai_model":        model,
		"prompt_length":   promptLength,
		"response_length": responseLength,
		"duration":        duration,
		"success":         success,
	})

	if err != nil {
		entry.WithError(err).Error("AI interaction failed")
	} else {
		entry.Info("AI interaction completed")
	}
}

// LogWebSocketEvent logs a WebSocket event
func LogWebSocketEvent(event string, clientID string, roomID string, err error) {
	entry := GetLogger().WithFields(logrus.Fields{
		"event":     event,
		"client_id": clientID,
		"room_id":   roomID,
	})

	if err != nil {
		entry.WithError(err).Error("WebSocket event failed")
	} else {
		entry.Info("WebSocket event completed")
	}
}

// LogAuthEvent logs an authentication event
func LogAuthEvent(event string, userID string, clientIP string, success bool, err error) {
	entry := GetLogger().WithFields(logrus.Fields{
		"event":     event,
		"user_id":   userID,
		"client_ip": clientIP,
		"success":   success,
	})

	if err != nil {
		entry.WithError(err).Error("Authentication event failed")
	} else {
		entry.Info("Authentication event completed")
	}
}
