package database

import (
	"authservice/internal/persistance/database/config"
	"context"
	"fmt"
	codecs "github.com/amsokol/mongo-go-driver-protobuf"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	Options "go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"time"
)

const (
	DatabaseTimeout = 10 * time.Second
)

func ProvideConfigProduction() config.DbConfig {
	return &config.DbConfigProduction{}
}

func ProvideConfigDevelopment() config.DbConfig {
	return &config.DbConfigDevelopment{}
}

func ProvideConfigTesting() config.DbConfig {
	return &config.DbConfigTesting{}
}

func ProvideDatabase(config config.DbConfig) *Database {
	db := &Database{}
	db.Configuration = config
	ctx, cancel := context.WithTimeout(context.Background(), DatabaseTimeout)
	defer cancel()
	connection := fmt.Sprintf("%s://%s:%s", config.Scheme(), config.HostName(), config.Port())
	reg := codecs.Register(bson.NewRegistryBuilder()).Build()

	credentials := Options.Credential{
		Username: config.User(),
		Password: config.Password(),
	}

	database, err := mongo.Connect(ctx, Options.Client().SetRegistry(reg).ApplyURI(connection).SetAuth(credentials))
	db.Client = database.Database(config.DatabaseName())
	if err != nil {
		log.Fatalf("failed to create new MongoDB client: %v", err)
	}
	return db
}

func ProvideTestDatabase() *Database {
	db := &Database{}
	db.Configuration = ProvideConfigTesting()
	ctx, cancel := context.WithTimeout(context.Background(), DatabaseTimeout)
	defer cancel()
	connection := fmt.Sprintf("%s://%s:%s", db.Configuration.Scheme(), db.Configuration.HostName(), db.Configuration.Port())
	reg := codecs.Register(bson.NewRegistryBuilder()).Build()

	credentials := Options.Credential{
		Username: db.Configuration.User(),
		Password: db.Configuration.Password(),
	}

	database, err := mongo.Connect(ctx, Options.Client().SetRegistry(reg).ApplyURI(connection).SetAuth(credentials))
	db.Client = database.Database(db.Configuration.DatabaseName())

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

	err = db.Client.Drop(context.Background())
	if err != nil {
		log.Fatalf("clean up of databse failed", err)
	}

	return db
}
