package packs

import (
	"context"
	"regexp"
	"testing"
	"time"

	"github.com/DATA-DOG/go-sqlmock"
	cp "github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane"
)

func TestPrepareManagedLifecycleTargetsUsesExplicitTransactionAndPositiveObservation(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()
	targets := []cp.ComponentManagedTarget{
		{TargetDomain: "test/a", PhysicalKeyBytes: []byte{'b', 0, '2'}},
		{TargetDomain: "test/a", PhysicalKeyBytes: []byte{'a', 0, '1'}},
	}
	canonical := []cp.ComponentManagedTarget{
		{TargetDomain: "test/a", PhysicalKeyBytes: []byte{'a', 0, '1'}},
		{TargetDomain: "test/a", PhysicalKeyBytes: []byte{'b', 0, '2'}},
	}
	mock.ExpectBegin()
	insert := regexp.QuoteMeta("INSERT INTO `_System_ManagedComponentTargetLock` (`TargetDomain`, `PhysicalKey`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `PhysicalKey` = VALUES(`PhysicalKey`)")
	for _, target := range canonical {
		mock.ExpectExec(insert).WithArgs([]byte(target.TargetDomain), target.PhysicalKeyBytes).WillReturnResult(sqlmock.NewResult(0, 1))
	}
	mock.ExpectCommit()
	observe := regexp.QuoteMeta("SELECT 1 FROM `_System_ManagedComponentTargetLock` WHERE `TargetDomain` = ? AND `PhysicalKey` = ? LIMIT 1")
	for _, target := range canonical {
		mock.ExpectQuery(observe).WithArgs([]byte(target.TargetDomain), target.PhysicalKeyBytes).WillReturnRows(sqlmock.NewRows([]string{"1"}).AddRow(1))
	}

	if err := prepareManagedLifecycleTargets(context.Background(), db, targets, time.Second, 1); err != nil {
		t.Fatal(err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}

func TestPrepareManagedLifecycleTargetsDoesNotTrustCommitResponseLoss(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()
	target := cp.ComponentManagedTarget{TargetDomain: "test/a", PhysicalKeyBytes: []byte("one")}
	mock.ExpectBegin()
	mock.ExpectExec(regexp.QuoteMeta("INSERT INTO `_System_ManagedComponentTargetLock` (`TargetDomain`, `PhysicalKey`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `PhysicalKey` = VALUES(`PhysicalKey`)")).
		WithArgs([]byte(target.TargetDomain), target.PhysicalKeyBytes).WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectCommit().WillReturnError(context.DeadlineExceeded)
	mock.ExpectQuery(regexp.QuoteMeta("SELECT 1 FROM `_System_ManagedComponentTargetLock` WHERE `TargetDomain` = ? AND `PhysicalKey` = ? LIMIT 1")).
		WithArgs([]byte(target.TargetDomain), target.PhysicalKeyBytes).WillReturnRows(sqlmock.NewRows([]string{"1"}).AddRow(1))

	if err := prepareManagedLifecycleTargets(context.Background(), db, []cp.ComponentManagedTarget{target}, time.Second, 1); err != nil {
		t.Fatalf("positive observation after lost commit response: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}
