package db

import (
	"log"
	"os"
	"time"

	"github.com/pkg/errors"
	"gorm.io/driver/postgres"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

const (
	// EnvDatabaseDriver is the key for the 'database driver' environment variable.
	EnvDatabaseDriver = "RUSHLINK_DATABASE_DRIVER"
	// EnvDatabasePath is the key for the 'database path' environment variable.
	EnvDatabasePath = "RUSHLINK_DATABASE_PATH"
	// EnvPostgresURL is the key for the 'postgresql URL' environment variable.
	EnvPostgresURL = "RUSHLINK_POSTGRES_URL"
	// EnvFileStorePath is the key for the environment variable locating the file store.
	EnvFileStorePath = "RUSHLINK_FILE_STORE_PATH"
)

// Database is the main rushlink database type.
//
// Open a database using OpenDBFromEnvironment(). Closing is not necessary.
// Only one instance of DB should exist in a program at any moment.
type Database = gorm.DB

var (
	gormLogger logger.Interface = logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
		SlowThreshold: 50 * time.Millisecond,
		LogLevel:      logger.Warn,
		Colorful:      true,
	})
	gormConfig = gorm.Config{Logger: gormLogger, PrepareStmt: true}
)

// OpenDBFromEnvironment tries to open an SQL database, described by
func OpenDBFromEnvironment() (*Database, error) {
	const envNotSetMsg = "%v environment variable is not set"

	driver, prs := os.LookupEnv(EnvDatabaseDriver)
	if !prs {
		return nil, errors.Errorf(envNotSetMsg, EnvDatabaseDriver)
	}
	switch driver {
	case "sqlite":
		path, prs := os.LookupEnv(EnvDatabasePath)
		if !prs {
			return nil, errors.Errorf(envNotSetMsg, EnvDatabasePath)
		}
		db, err := gorm.Open(sqlite.Open(path), &gormConfig)
		if err != nil {
			return nil, err
		}
		return db, nil
	case "postgres":
		dsn, prs := os.LookupEnv(EnvPostgresURL)
		if !prs {
			return nil, errors.Errorf(envNotSetMsg, EnvPostgresURL)
		}
		db, err := gorm.Open(postgres.Open(dsn), &gormConfig)
		if err != nil {
			return nil, err
		}
		return db, nil
	default:
		return nil, errors.Errorf("RUSHLINK_DATABASE_DRIVER should be either 'sqlite' or 'postgres' (not '%v'), "+
			"for more info see <https://stackoverflow.com/q/3582552/5207081>", driver)
	}
}