package packs

import (
	"context"
	"database/sql"
	"regexp"
	"strings"
	"testing"

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

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

	mock.ExpectQuery(regexp.QuoteMeta("SELECT `ApiName`, `CustomSetting`, COALESCE(`IsCustomized`, 0), COALESCE(`IsDeleted`, 0) FROM `_System_Object`")).
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "CustomSetting", "IsCustomized", "IsDeleted"}).
			AddRow("Countries_Region__c", sql.NullBool{Valid: false}, 0, 0))

	err = VerifyPackObjectCustomSetting(db, "salesforce-crm-standard", []ObjectSpec{{
		APIName:       "Countries_Region__c",
		CustomSetting: true,
	}}, ManageabilityLocked)
	if err == nil {
		t.Fatal("VerifyPackObjectCustomSetting = nil, want drift error")
	}
	if !strings.Contains(err.Error(), "CustomSetting") {
		t.Fatalf("VerifyPackObjectCustomSetting error = %v, want CustomSetting detail", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	mock.ExpectQuery(regexp.QuoteMeta("SELECT `ApiName`, `CustomSetting`, COALESCE(`IsCustomized`, 0), COALESCE(`IsDeleted`, 0) FROM `_System_Object`")).
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "CustomSetting", "IsCustomized", "IsDeleted"}).
			AddRow("Countries_Region__c", true, 0, 0))

	if err := VerifyPackObjectCustomSetting(db, "salesforce-crm-standard", []ObjectSpec{{
		APIName:       "Countries_Region__c",
		CustomSetting: true,
	}}, ManageabilityLocked); err != nil {
		t.Fatalf("VerifyPackObjectCustomSetting = %v, want nil", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	query := regexp.QuoteMeta("UPDATE `_System_Object` SET `CustomSetting` = ?, `LastModifiedDate` = NOW() WHERE LOWER(`ApiName`) = LOWER(?) AND COALESCE(`IsDeleted`, 0) = 0 AND (`CustomSetting` IS NULL OR COALESCE(`CustomSetting`, 0) <> ?)")
	mock.ExpectExec(query).
		WithArgs(1, "Countries_Region__c", 1).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec(query).
		WithArgs(0, "Widget__c", 0).
		WillReturnResult(sqlmock.NewResult(0, 1))

	updated, err := backfillObjectMetadataCustomSettingForSpecs(context.Background(), db, []ObjectSpec{
		{APIName: "Countries_Region__c", CustomSetting: true},
		{APIName: "Widget__c", CustomSetting: false},
	})
	if err != nil {
		t.Fatalf("backfillObjectMetadataCustomSettingForSpecs = %v", err)
	}
	if updated != 2 {
		t.Fatalf("backfillObjectMetadataCustomSettingForSpecs updated = %d, want 2", updated)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}
