package gormdb

import (
	"fmt"
	"time"

	"github.com/UpmeshLTD/urus-aio/mdm/config"
	"github.com/UpmeshLTD/urus-aio/mdm/log"
	"github.com/avast/retry-go"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type GormDB interface {
	// DB returns the internal gorm.DB instance.
	DB() *gorm.DB
}

type gormImpl struct {
	db *gorm.DB
}

func NewGormDB(logger log.Logger, cfg config.Config) (GormDB, error) {
	logger = log.With(logger, "component", "GormDB")

	dbConfig := cfg.GetDatabaseConfig()

	dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=disable",
		dbConfig.Host, dbConfig.Username, dbConfig.Password, dbConfig.Database, dbConfig.Port)

	var (
		db  *gorm.DB
		err error
	)

	err = retry.Do(func() error {
		db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
		return err
	},
		retry.Attempts(dbConfig.RetryAttempts),
		retry.Delay(time.Second),
	)

	if err != nil {
		logger.Errorw("failed to initialize GormDB", "error", err)
		return nil, err
	}

	logger.Info("successfully initialize GormDB")
	if cfg.GetAppConfig().Environment == "development" {
		db = db.Debug()
	}

	return &gormImpl{
		db: db,
	}, nil
}

func Wrap(db *gorm.DB) (GormDB, error) {
	return &gormImpl{
		db: db,
	}, nil
}

// DB returns the internal gorm.DB instance.
func (impl *gormImpl) DB() *gorm.DB {
	return impl.db
}
