package controlplane

import (
	"context"
	"strings"
	"testing"

	sqlmock "github.com/DATA-DOG/go-sqlmock"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

func expectPersistedRuntimeOnlyInstalledPackForVerify(mock sqlmock.Sqlmock) {
	mock.ExpectQuery("SELECT COLUMN_NAME\\s+FROM INFORMATION_SCHEMA\\.COLUMNS").
		WithArgs(
			"_System_InstalledPack",
			"RuntimeObjectSpecDeclarations",
			"RuntimeRelatedListRules",
			"RuntimeSearchScopeOrder",
			"RuntimeSearchAllDefaultFields",
		).
		WillReturnRows(sqlmock.NewRows([]string{"COLUMN_NAME"}).
			AddRow("RuntimeObjectSpecDeclarations").
			AddRow("RuntimeRelatedListRules").
			AddRow("RuntimeSearchScopeOrder").
			AddRow("RuntimeSearchAllDefaultFields"))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM INFORMATION_SCHEMA\\.COLUMNS").
		WithArgs("_System_InstalledPack", "RuntimeStartupShallowDeclarations").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM INFORMATION_SCHEMA\\.COLUMNS").
		WithArgs("_System_InstalledPack", "RuntimeFormulaFunctionBundles").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectQuery("SELECT Name, Category, AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision,\\s+RuntimeObjectSpecDeclarations, RuntimeRelatedListRules, RuntimeSearchScopeOrder, RuntimeSearchAllDefaultFields, RuntimeStartupShallowDeclarations\\s+FROM _System_InstalledPack").
		WillReturnRows(sqlmock.NewRows([]string{
			"Name", "Category", "AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision",
			"RuntimeObjectSpecDeclarations", "RuntimeRelatedListRules", "RuntimeSearchScopeOrder", "RuntimeSearchAllDefaultFields", "RuntimeStartupShallowDeclarations",
		}).AddRow(
			"persisted-pack",
			"app-pack",
			"",
			"1",
			"",
			"",
			"",
			"[]",
			"[]",
			"[]",
			"[]",
			"[]",
		))
}

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

	expectPersistedRuntimeOnlyInstalledPackForVerify(mock)

	if err := registerInstalledRuntimeMetadataForVerify(context.Background(), db, false, options.ComponentKindRegistrationSet); err != nil {
		t.Fatalf("registerInstalledRuntimeMetadataForVerify(deep=false): %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	expectPersistedRuntimeOnlyInstalledPackForVerify(mock)

	err = registerInstalledRuntimeMetadataForVerify(context.Background(), db, true, packs.ComponentKindRegistrationSet{})
	if err == nil || !strings.Contains(err.Error(), "runtime declaration is not source-backed active state") {
		t.Fatalf("registerInstalledRuntimeMetadataForVerify(deep=true) error = %v, want source identity validation failure", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}
