package packs

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

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

func legacyChildCloneRulesSelectSQLForTest() string {
	return regexp.QuoteMeta("SELECT `Id`, `ApiName`, COALESCE(`IsCustom`, 0), `ChildCloneRules`, COALESCE(`ChildCloneRulesPackName`, ''), COALESCE(`ChildCloneRulesPackBusinessKey`, ''), COALESCE(`ChildCloneRulesPackManageability`, ''), `ChildCloneRulesPackValue` FROM `_System_Object` WHERE COALESCE(`IsDeleted`, 0) = 0 AND `ChildCloneRules` IS NOT NULL AND COALESCE(`ChildCloneRulesCustomized`, 0) = 0 ORDER BY `Id`")
}

func legacyChildCloneRulesRowsForTest() *sqlmock.Rows {
	return sqlmock.NewRows([]string{"Id", "ApiName", "IsCustom", "ChildCloneRules", "ChildCloneRulesPackName", "ChildCloneRulesPackBusinessKey", "ChildCloneRulesPackManageability", "ChildCloneRulesPackValue"})
}

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

	mock.ExpectQuery(legacyChildCloneRulesSelectSQLForTest()).
		WillReturnRows(legacyChildCloneRulesRowsForTest().
			AddRow("obj_account", "Account", 0, `[{"parentLookupField":"ParentId","sourceObject":"Contact","sourceLookupField":"AccountId","targetObject":"Contact","targetLookupField":"AccountId","fieldMappings":{"LastName":"LastName"}}]`, "", "", "", sql.NullString{}))

	updated, err := ClassifyLegacyChildCloneRulesCustomized(context.Background(), db)
	if err != nil {
		t.Fatalf("ClassifyLegacyChildCloneRulesCustomized = %v", err)
	}
	if updated != 0 {
		t.Fatalf("updated = %d, want 0", updated)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	mock.ExpectQuery(legacyChildCloneRulesSelectSQLForTest()).
		WillReturnRows(legacyChildCloneRulesRowsForTest().
			AddRow("obj_custom", "Custom__c", 1, `[{"parentLookupField":"Parent__c","sourceObject":"Child__c","sourceLookupField":"Parent__c","targetObject":"Child__c","targetLookupField":"Parent__c","fieldMappings":{"Name":"Name"}}]`, "", "", "", sql.NullString{}))

	updated, err := ClassifyLegacyChildCloneRulesCustomized(context.Background(), db)
	if err != nil {
		t.Fatalf("ClassifyLegacyChildCloneRulesCustomized = %v", err)
	}
	if updated != 0 {
		t.Fatalf("updated = %d, want 0", updated)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	live := `[{"parentLookupField":"ParentId","sourceObject":"Contact","sourceLookupField":"AccountId","targetObject":"Contact","targetLookupField":"AccountId","fieldMappings":{"LastName":"LastName"}}]`
	mock.ExpectQuery(legacyChildCloneRulesSelectSQLForTest()).
		WillReturnRows(legacyChildCloneRulesRowsForTest().
			AddRow("obj_account", "Account", 0, live, "salesforce-crm-standard", "objects", "defaults_only", sql.NullString{String: live, Valid: true}))

	updated, err := ClassifyLegacyChildCloneRulesCustomized(context.Background(), db)
	if err != nil {
		t.Fatalf("ClassifyLegacyChildCloneRulesCustomized = %v", err)
	}
	if updated != 0 {
		t.Fatalf("updated = %d, want 0", updated)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	live := `[{"parentLookupField":"Parent__c","sourceObject":"Child__c","sourceLookupField":"Parent__c","targetObject":"Child__c","targetLookupField":"Parent__c","fieldMappings":{"Name":"Name"}}]`
	mock.ExpectQuery(legacyChildCloneRulesSelectSQLForTest()).
		WillReturnRows(legacyChildCloneRulesRowsForTest().
			AddRow("obj_custom", "Custom__c", 1, live, "jira-like-sample", "objects", "defaults_only", sql.NullString{String: live, Valid: true}))

	updated, err := ClassifyLegacyChildCloneRulesCustomized(context.Background(), db)
	if err != nil {
		t.Fatalf("ClassifyLegacyChildCloneRulesCustomized = %v", err)
	}
	if updated != 0 {
		t.Fatalf("updated = %d, want 0", updated)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	live := `[{"parentLookupField":"Parent__c","sourceObject":"Child__c","sourceLookupField":"Parent__c","targetObject":"Child__c","targetLookupField":"Parent__c","fieldMappings":{"Name":"Name"}}]`
	mock.ExpectQuery(legacyChildCloneRulesSelectSQLForTest()).
		WillReturnRows(legacyChildCloneRulesRowsForTest().
			AddRow("obj_custom", "Custom__c", 1, live, "jira-like-sample", "objects", "defaults_only", sql.NullString{}))
	mock.ExpectBegin()
	mock.ExpectExec(regexp.QuoteMeta("UPDATE `_System_Object` SET `ChildCloneRulesCustomized` = 1, `LastModifiedDate` = NOW() WHERE `Id` = ? AND COALESCE(`ChildCloneRulesCustomized`, 0) = 0")).
		WithArgs("obj_custom").
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectCommit()

	updated, err := ClassifyLegacyChildCloneRulesCustomized(context.Background(), db)
	if err != nil {
		t.Fatalf("ClassifyLegacyChildCloneRulesCustomized = %v", err)
	}
	if updated != 1 {
		t.Fatalf("updated = %d, want 1", updated)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

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

	live := `[{"parentLookupField":"Parent__c","sourceObject":"Child__c","sourceLookupField":"Parent__c","targetObject":"Child__c","targetLookupField":"Parent__c","fieldMappings":{"Name":"Name"}}]`
	mock.ExpectQuery(legacyChildCloneRulesSelectSQLForTest()).
		WillReturnRows(legacyChildCloneRulesRowsForTest().
			AddRow("obj_custom", "Custom__c", 1, live, "jira-like-sample", "objects", "locked", sql.NullString{}))

	updated, err := ClassifyLegacyChildCloneRulesCustomized(context.Background(), db)
	if err != nil {
		t.Fatalf("ClassifyLegacyChildCloneRulesCustomized = %v", err)
	}
	if updated != 0 {
		t.Fatalf("updated = %d, want 0", updated)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestBackfillChildCloneRulesCustomizedRecordsMigrationStamp(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 = ? LIMIT 1")).
		WithArgs(migrationIdBackfillChildCloneRulesCustomized).
		WillReturnRows(sqlmock.NewRows([]string{"present"}))
	mock.ExpectQuery(legacyChildCloneRulesSelectSQLForTest()).
		WillReturnRows(legacyChildCloneRulesRowsForTest())
	mock.ExpectExec(regexp.QuoteMeta("INSERT INTO _System_Migration")).
		WithArgs(migrationIdBackfillChildCloneRulesCustomized, 1, sqlmock.AnyArg()).
		WillReturnResult(sqlmock.NewResult(0, 1))

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