package controlplane

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

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

func TestBackfillWebhookSecretKeyReadProtectionStampsLegacyField(t *testing.T) {
	db, mock, cleanup := newWebhookSecretKeyBackfillSQLMock(t)
	defer cleanup()

	mock.ExpectQuery(regexp.QuoteMeta("SELECT 1 FROM _System_Migration WHERE Id = ? LIMIT 1")).
		WithArgs(migrationIdBackfillWebhookSecretKeyReadProtection).
		WillReturnError(sql.ErrNoRows)
	mock.ExpectExec(regexp.QuoteMeta(webhookSecretKeyReadProtectionUpdateSQL)).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectQuery(regexp.QuoteMeta(webhookSecretKeyReadProtectionRemainingSQL)).
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectExec(regexp.QuoteMeta("INSERT INTO _System_Migration (Id, Version, Description, AppliedAt, CreatedDate, LastModifiedDate)")).
		WithArgs(
			migrationIdBackfillWebhookSecretKeyReadProtection,
			1,
			"Backfill readProtectionPolicy=blocked for legacy _System_Webhook.SecretKey field metadata before removing the generic sensitive-field fallback.",
		).
		WillReturnResult(sqlmock.NewResult(1, 1))

	touched, err := BackfillWebhookSecretKeyReadProtection(context.Background(), db)
	if err != nil {
		t.Fatalf("BackfillWebhookSecretKeyReadProtection() error = %v", err)
	}
	if touched != 1 {
		t.Fatalf("BackfillWebhookSecretKeyReadProtection() touched = %d, want 1", touched)
	}
}

func TestBackfillWebhookSecretKeyReadProtectionSkipsWhenStamped(t *testing.T) {
	db, mock, cleanup := newWebhookSecretKeyBackfillSQLMock(t)
	defer cleanup()

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

	touched, err := BackfillWebhookSecretKeyReadProtection(context.Background(), db)
	if err != nil {
		t.Fatalf("BackfillWebhookSecretKeyReadProtection() error = %v", err)
	}
	if touched != 0 {
		t.Fatalf("BackfillWebhookSecretKeyReadProtection() touched = %d, want 0", touched)
	}
}

func TestBackfillWebhookSecretKeyReadProtectionFailsWhenClosureFindsUnprotectedRows(t *testing.T) {
	db, mock, cleanup := newWebhookSecretKeyBackfillSQLMock(t)
	defer cleanup()

	mock.ExpectQuery(regexp.QuoteMeta("SELECT 1 FROM _System_Migration WHERE Id = ? LIMIT 1")).
		WithArgs(migrationIdBackfillWebhookSecretKeyReadProtection).
		WillReturnError(sql.ErrNoRows)
	mock.ExpectExec(regexp.QuoteMeta(webhookSecretKeyReadProtectionUpdateSQL)).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectQuery(regexp.QuoteMeta(webhookSecretKeyReadProtectionRemainingSQL)).
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))

	_, err := BackfillWebhookSecretKeyReadProtection(context.Background(), db)
	if err == nil {
		t.Fatal("BackfillWebhookSecretKeyReadProtection() error = nil, want closure failure")
	}
	if !strings.Contains(err.Error(), "SecretKey") || !strings.Contains(err.Error(), "readProtectionPolicy=blocked") {
		t.Fatalf("BackfillWebhookSecretKeyReadProtection() error = %v, want SecretKey closure failure", err)
	}
}

func newWebhookSecretKeyBackfillSQLMock(t *testing.T) (*sql.DB, sqlmock.Sqlmock, func()) {
	t.Helper()
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock.New: %v", err)
	}
	cleanup := func() {
		if err := mock.ExpectationsWereMet(); err != nil {
			t.Fatalf("unmet SQL expectations: %v", err)
		}
		db.Close()
	}
	return db, mock, cleanup
}
