package migrations

import (
	"bytes"
	"errors"
	"fmt"
	"log/slog"
	"strconv"

	"git.sr.ht/~ashkeel/strimertul/database"
)

const (
	SchemaKey     = "strimertul/schema-version"
	SchemaVersion = 4
)

// GetCurrentSchemaVersion returns the current schema version
// from the database, or 0 if it's not set (v3.x.x or earlier)
func GetCurrentSchemaVersion(db database.Database) (int, error) {
	versionStr, err := db.GetKey(SchemaKey)
	if err != nil {
		if errors.Is(err, database.ErrEmptyKey) {
			return 0, nil
		}
	}

	if versionStr == "" {
		return 0, nil
	}

	return strconv.Atoi(versionStr)
}

func Run(driver database.Driver, db database.Database, logger *slog.Logger) (err error) {
	// Make a backup of the database
	var buffer bytes.Buffer
	if err = driver.Backup(&buffer); err != nil {
		return fmt.Errorf("failed to backup database: %w", err)
	}
	// Restore the backup if an error occurs
	defer func() {
		if err != nil {
			restoreErr := driver.Restore(bytes.NewReader(buffer.Bytes()))
			if restoreErr != nil {
				logger.Error("Failed to restore database from backup", "error", restoreErr)
			}
		}
	}()

	// Get the current schema version
	var currentVersion int
	currentVersion, err = GetCurrentSchemaVersion(db)
	if err != nil {
		return
	}

	// Migrate from v3.x.x to v4.0.0
	if currentVersion < 4 {
		if err = migrateToV4(db, logger); err != nil {
			return
		}
	}

	// Set the new schema version
	if err = db.PutKey(SchemaKey, strconv.Itoa(SchemaVersion)); err != nil {
		return
	}

	return
}
