package mongo

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/url"
	"time"

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

type ConnectDeps struct {
	Configuration *Configuration
	Timeout       time.Duration
}

func Connect(ctx context.Context, deps *ConnectDeps) (*mongo.Database, error) {
	if deps == nil {
		return nil, ErrEmptyArgs
	}

	mongoURI := &url.URL{
		Scheme: "mongodb",
		Host:   net.JoinHostPort(deps.Configuration.Host, deps.Configuration.Port),
	}

	connectionOptions := options.Client().
		ApplyURI(mongoURI.String()).
		SetAuth(options.Credential{
			AuthMechanism: "SCRAM-SHA-1",
			AuthSource:    deps.Configuration.Auth,
			Username:      deps.Configuration.User,
			Password:      deps.Configuration.Password,
		})

	ticker := time.NewTicker(1 * time.Second)
	timeoutExceeded := time.After(deps.Timeout)

	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			connection, err := mongo.Connect(ctx, connectionOptions)
			if err == nil {
				return connection.Database(deps.Configuration.DatabaseName), nil
			}

			log.Printf("failed to connect to db <%s>: %s", mongoURI.String(), err.Error())
		case <-timeoutExceeded:
			return nil, fmt.Errorf("db connection <%s> failed after %d timeout", mongoURI.String(), deps.Timeout)
		default:
			time.Sleep(1 * time.Second)
		}
	}
}
