package mongodb

import (
	"context"
	"fmt"
	"log"
	"math/rand"
	"time"

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

// connectWithRetry attempts to connect to MongoDB with exponential backoff
func connectWithRetry(ctx context.Context, uri string) (*mongo.Client, error) {
	var client *mongo.Client
	var err error
	maxRetries := 5
	retryDelay := time.Second * 2

	for attempt := 1; attempt <= maxRetries; attempt++ {
		// Create MongoDB client
		client, err = mongo.NewClient(options.Client().ApplyURI(uri))
		if err != nil {
			return nil, fmt.Errorf("failed to create MongoDB client: %w", err)
		}

		// Create context with timeout for this attempt
		connectCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
		defer cancel()

		// Attempt connection
		err = client.Connect(connectCtx)
		if err == nil {
			// Test connection with ping
			pingCtx, pingCancel := context.WithTimeout(ctx, 5*time.Second)
			defer pingCancel()

			err = client.Ping(pingCtx, nil)
			if err == nil {
				// Successfully connected and pinged
				return client, nil
			}
		}

		// Connection failed, clean up and retry
		_ = client.Disconnect(context.Background())

		if attempt < maxRetries {
			// Add jitter to retry delay
			jitter := time.Duration(rand.Intn(1000)) * time.Millisecond
			sleepTime := retryDelay + jitter

			log.Printf("MongoDB connection attempt %d failed: %v. Retrying in %v...",
				attempt, err, sleepTime)

			time.Sleep(sleepTime)
			retryDelay *= 2 // Exponential backoff
		}
	}

	return nil, fmt.Errorf("failed to connect to MongoDB after %d attempts: %w",
		maxRetries, err)
}
