package customlogger

import (
	"context"
	"fmt"
	"log/slog"
	"os"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var LogLevels = map[string]slog.Level{
	"debug": slog.LevelDebug,
	"info":  slog.LevelInfo,
	"warn":  slog.LevelWarn,
	"error": slog.LevelError,
}
var Environment = map[string]string{
	"dev":  "development",
	"prod": "production",
}

func NewLogger(env string, lvl slog.Level) *slog.Logger {
	var logHandler slog.Handler

	err := os.MkdirAll("logs", os.ModePerm)
	if err != nil {
		panic("Failed to create log directory: " + err.Error())
	}

	file, err := os.OpenFile("logs/app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		panic("Failed to open log file: " + err.Error())
	}

	switch env {
	case "development":
		logHandler = slog.NewTextHandler(file, &slog.HandlerOptions{
			Level: lvl,
		})
	default:
		logHandler = slog.NewJSONHandler(file, &slog.HandlerOptions{
			Level: lvl,
		})
	}

	logger := slog.New(logHandler).With(slog.Group(
		"service_info",
		slog.String("env", env),
	),
	)

	return logger
}

// MongoLogger wraps a MongoDB connection and logger
type MongoLogger struct {
	client     *mongo.Client
	collection *mongo.Collection
}

// NewMongoLogger creates a new MongoDB-connected logger
func NewMongoLogger(mongoURI, dbName, collectionName string) (*MongoLogger, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 1. Connect to MongoDB with retries
	client, err := mongo.Connect(ctx, options.Client().
		ApplyURI(mongoURI).
		SetServerAPIOptions(options.ServerAPI(options.ServerAPIVersion1)),
	)
	if err != nil {
		return nil, fmt.Errorf("MongoDB connection failed: %w", err)
	}

	// 2. Verify connection
	err = client.Ping(ctx, nil)
	if err != nil {
		return nil, fmt.Errorf("MongoDB ping failed: %w", err)
	}

	// 3. Get collection handle
	coll := client.Database(dbName).Collection(collectionName)

	return &MongoLogger{
		client:     client,
		collection: coll,
	}, nil
}

// Log writes a log entry to MongoDB
func (ml *MongoLogger) Log(level, message string, attrs map[string]interface{}) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	_, err := ml.collection.InsertOne(ctx, bson.M{
		"timestamp": time.Now(),
		"level":     level,
		"message":   message,
		"attrs":     attrs,
	})
	return err
}

// Close safely disconnects from MongoDB
func (ml *MongoLogger) Close() error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	return ml.client.Disconnect(ctx)
}
