package controlplane

import (
	"context"
	"testing"

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

// TestMigratePackInstallIdBackfill_FillsEmptyRowsOnly verifies that
// backfillBlankPackInstallIds (the idempotent inner function) issues an
// UPDATE for each row with a blank PackInstallId while leaving rows that
// already carry a value untouched.
//
// The WHERE predicate in the UPDATE already guards against touching non-blank
// rows even if they appeared in the SELECT result — but we model the SQL layer
// behaviour here, not in-memory logic, so the mock asserts the SQL contract.
func TestMigratePackInstallIdBackfill_FillsEmptyRowsOnly(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	// SELECT returns two rows with blank PackInstallId.
	selectRows := sqlmock.NewRows([]string{"Id"}).
		AddRow("pack-a").
		AddRow("pack-b")
	mock.ExpectQuery(`SELECT Id FROM _System_InstalledPack WHERE PackInstallId = '' OR PackInstallId IS NULL`).
		WillReturnRows(selectRows)

	// Two UPDATE calls — one per row. Each must supply a non-empty UUID
	// and include the idempotency WHERE guard.
	mock.ExpectExec(`UPDATE _System_InstalledPack SET PackInstallId = \? WHERE Id = \? AND \(PackInstallId = '' OR PackInstallId IS NULL\)`).
		WithArgs(sqlmock.AnyArg(), "pack-a").
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec(`UPDATE _System_InstalledPack SET PackInstallId = \? WHERE Id = \? AND \(PackInstallId = '' OR PackInstallId IS NULL\)`).
		WithArgs(sqlmock.AnyArg(), "pack-b").
		WillReturnResult(sqlmock.NewResult(0, 1))

	n, err := backfillBlankPackInstallIds(context.Background(), db)
	if err != nil {
		t.Fatalf("backfillBlankPackInstallIds: %v", err)
	}
	if n != 2 {
		t.Fatalf("backfillBlankPackInstallIds updated %d rows, want 2", n)
	}

	if err2 := mock.ExpectationsWereMet(); err2 != nil {
		t.Fatalf("sql expectations: %v", err2)
	}
}

// TestMigratePackInstallIdBackfill_NoOpWhenAllRowsFilled verifies that when
// the SELECT returns no rows the function returns 0 and issues no UPDATEs.
func TestMigratePackInstallIdBackfill_NoOpWhenAllRowsFilled(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	mock.ExpectQuery(`SELECT Id FROM _System_InstalledPack WHERE PackInstallId = '' OR PackInstallId IS NULL`).
		WillReturnRows(sqlmock.NewRows([]string{"Id"}))

	n, err := backfillBlankPackInstallIds(context.Background(), db)
	if err != nil {
		t.Fatalf("backfillBlankPackInstallIds: %v", err)
	}
	if n != 0 {
		t.Fatalf("backfillBlankPackInstallIds updated %d rows, want 0", n)
	}

	if err2 := mock.ExpectationsWereMet(); err2 != nil {
		t.Fatalf("sql expectations: %v", err2)
	}
}
