package bootstrapimpl

import (
	"context"
	"errors"
	"regexp"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
)

func TestNormalizeLegacyDDLDefaultsRunsOnceAndRecordsStamp(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	mock.ExpectQuery(regexp.QuoteMeta("SELECT 1 FROM _System_Migration WHERE Id = ?")).
		WithArgs(migrationIdNormalizeLegacyDefaults).
		WillReturnRows(sqlmock.NewRows([]string{"_"}))
	mock.ExpectBegin()
	mock.ExpectExec(regexp.QuoteMeta("UPDATE `_System_Field`")).
		WillReturnResult(sqlmock.NewResult(0, 2))
	mock.ExpectExec(regexp.QuoteMeta("INSERT INTO _System_Migration")).
		WithArgs(migrationIdNormalizeLegacyDefaults, 1, sqlmock.AnyArg()).
		WillReturnResult(sqlmock.NewResult(1, 1))
	mock.ExpectCommit()

	if err := normalizeLegacyDDLDefaults(context.Background(), db); err != nil {
		t.Fatalf("normalizeLegacyDDLDefaults returned err = %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestNormalizeLegacyDDLDefaultsRollsBackWhenStampFails(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	stampErr := errors.New("stamp insert failed")
	mock.ExpectQuery(regexp.QuoteMeta("SELECT 1 FROM _System_Migration WHERE Id = ?")).
		WithArgs(migrationIdNormalizeLegacyDefaults).
		WillReturnRows(sqlmock.NewRows([]string{"_"}))
	mock.ExpectBegin()
	mock.ExpectExec(regexp.QuoteMeta("UPDATE `_System_Field`")).
		WillReturnResult(sqlmock.NewResult(0, 2))
	mock.ExpectExec(regexp.QuoteMeta("INSERT INTO _System_Migration")).
		WithArgs(migrationIdNormalizeLegacyDefaults, 1, sqlmock.AnyArg()).
		WillReturnError(stampErr)
	mock.ExpectRollback()

	err = normalizeLegacyDDLDefaults(context.Background(), db)
	if !errors.Is(err, stampErr) {
		t.Fatalf("normalizeLegacyDDLDefaults err = %v, want wrapping %v", err, stampErr)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestNormalizeLegacyDDLDefaultsSkipsWhenStamped(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	mock.ExpectQuery(regexp.QuoteMeta("SELECT 1 FROM _System_Migration WHERE Id = ?")).
		WithArgs(migrationIdNormalizeLegacyDefaults).
		WillReturnRows(sqlmock.NewRows([]string{"_"}).AddRow(1))

	if err := normalizeLegacyDDLDefaults(context.Background(), db); err != nil {
		t.Fatalf("normalizeLegacyDDLDefaults returned err = %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}
