package bootstrapimpl

import (
	"errors"
	"regexp"
	"testing"

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

func TestEnsureIndexesWorkerCountDefaultsWhenUnset(t *testing.T) {
	t.Setenv(envEnsureIndexesWorkers, "")

	if got := ensureIndexesWorkerCount(); got != defaultEnsureIndexesWorkers {
		t.Fatalf("ensureIndexesWorkerCount() = %d, want default %d", got, defaultEnsureIndexesWorkers)
	}
}

func TestEnsureIndexesWorkerCountUsesPositiveOverride(t *testing.T) {
	t.Setenv(envEnsureIndexesWorkers, "3")

	if got := ensureIndexesWorkerCount(); got != 3 {
		t.Fatalf("ensureIndexesWorkerCount() = %d, want 3", got)
	}
}

func TestEnsureIndexesWorkerCountFallsBackOnInvalidValues(t *testing.T) {
	for _, raw := range []string{"0", "-1", "abc", "  "} {
		t.Run(raw, func(t *testing.T) {
			t.Setenv(envEnsureIndexesWorkers, raw)

			if got := ensureIndexesWorkerCount(); got != defaultEnsureIndexesWorkers {
				t.Fatalf("ensureIndexesWorkerCount() with %q = %d, want default %d", raw, got, defaultEnsureIndexesWorkers)
			}
		})
	}
}

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

	mock.ExpectQuery(regexp.QuoteMeta(
		"SELECT `TableName`, COALESCE(`IsDeleted`, 0) FROM `_System_Table` WHERE COALESCE(`IsManaged`, 0) = 0",
	)).WillReturnRows(sqlmock.NewRows([]string{"TableName", "IsDeleted"}).
		AddRow("LeadHistory", 0))

	missing, err := getMissingPhysicalTables(db, []string{"leadhistory"}, nil)
	if err != nil {
		t.Fatalf("getMissingPhysicalTables: %v", err)
	}
	if len(missing) != 0 {
		t.Fatalf("missing = %v, want active unmanaged table excluded", missing)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	mock.ExpectQuery(regexp.QuoteMeta(
		"SELECT `TableName`, COALESCE(`IsDeleted`, 0) FROM `_System_Table` WHERE COALESCE(`IsManaged`, 0) = 0",
	)).WillReturnRows(sqlmock.NewRows([]string{"TableName", "IsDeleted"}))

	missing, err := getMissingPhysicalTables(db, []string{"leadhistory"}, nil)
	if err != nil {
		t.Fatalf("getMissingPhysicalTables: %v", err)
	}
	if len(missing) != 1 || missing[0] != "leadhistory" {
		t.Fatalf("missing = %v, want [leadhistory]", missing)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	mock.ExpectQuery(regexp.QuoteMeta(
		"SELECT `TableName`, COALESCE(`IsDeleted`, 0) FROM `_System_Table` WHERE COALESCE(`IsManaged`, 0) = 0",
	)).WillReturnRows(sqlmock.NewRows([]string{"TableName", "IsDeleted"}).
		AddRow("LeadHistory", 1))

	missing, err := getMissingPhysicalTables(db, []string{"leadhistory"}, nil)
	if err != nil {
		t.Fatalf("getMissingPhysicalTables: %v", err)
	}
	if len(missing) != 1 || missing[0] != "leadhistory" {
		t.Fatalf("missing = %v, want deleted registry row to leave table discoverable", missing)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	mock.ExpectQuery(regexp.QuoteMeta(
		"SELECT `TableName`, COALESCE(`IsDeleted`, 0) FROM `_System_Table` WHERE COALESCE(`IsManaged`, 0) = 0",
	)).WillReturnError(errors.New("registry unavailable"))

	missing, err := getMissingPhysicalTables(db, []string{"leadhistory"}, nil)
	if err == nil || err.Error() != "registry unavailable" {
		t.Fatalf("getMissingPhysicalTables error = %v, want registry unavailable", err)
	}
	if missing != nil {
		t.Fatalf("missing = %v, want nil on registry read failure", missing)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}
