package database

import (
	"context"
	"fmt"
	"go.mongodb.org/mongo-driver/mongo/readpref"
	"log"
	"os"
	"time"

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

type Service interface {
	Health() map[string]string
	GetDB() *mongo.Database
}

type service struct {
	client *mongo.Client
	db     *mongo.Database
}

var (
	host = os.Getenv("MONGODB_DEV_HOST")
	port = os.Getenv("MONGODB_DEV_PORT")
	user = os.Getenv("MONGODB_DEV_USER")
	pass = os.Getenv("MONGODB_DEV_PASS")
)

func New(database string) Service {
	mongoURI := fmt.Sprintf("mongodb://%s:%s@%s:%s/%s?authSource=admin",
		user, pass, host, port, database)

	var client *mongo.Client
	var err error
	log.Println("Connecting to MongoDB...")
	log.Println(mongoURI)
	clientOptions := options.Client().ApplyURI(mongoURI)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	for i := 0; i < 5; i++ {
		client, err = mongo.Connect(ctx, clientOptions)
		if err == nil {
			log.Println("Connected to MongoDB")
			break
		}
		log.Printf("Attempt %d: Failed to connect to MongoDB, retrying in 5 seconds...\n", i+1)
		time.Sleep(5 * time.Second)
	}

	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	// Verify connection
	if err = client.Ping(ctx, readpref.Primary()); err != nil {
		log.Println("Failed to connect to MongoDB!!!")
		log.Fatalf("Failed to connect to database: %v", err)
	}

	log.Println("Successfully connected to MongoDB!")

	return &service{
		client: client,
		db:     client.Database(database),
	}
}

func (s *service) Health() map[string]string {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	status := map[string]string{
		"status":  "up",
		"message": "MongoDB connection is healthy",
	}

	if err := s.client.Ping(ctx, nil); err != nil {
		status["status"] = "down"
		status["error"] = err.Error()
		status["message"] = "Connection to MongoDB failed"
	}

	return status
}

func (s *service) GetDB() *mongo.Database {
	return s.db
}
