package persistence

import (
	"context"
	"errors"
	"testing"
	"time"

	apperrors "github.com/nexuscrm/kernel/pkg/errors"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestManagedRowMutationPredicateMissUsesCurrentReadOnTiDB(t *testing.T) {
	db, cleanup := openSchemaDDLTiDB(t)
	defer cleanup()

	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
	defer cancel()
	if _, err := db.ExecContext(ctx, `CREATE TABLE _System_RecordType (
		Id VARCHAR(255) PRIMARY KEY,
		ObjectId VARCHAR(255) NOT NULL,
		Description TEXT NULL,
		CatalogNamespaceId VARBINARY(128) NULL,
		CatalogLocalKey VARBINARY(128) NULL,
		UNIQUE KEY uq_record_type_catalog_key (
			ObjectId,
			CatalogNamespaceId,
			CatalogLocalKey
		)
	)`); err != nil {
		t.Fatalf("create RecordType fixture: %v", err)
	}
	if _, err := db.ExecContext(ctx, `INSERT INTO _System_RecordType
		(Id, ObjectId, Description, CatalogNamespaceId, CatalogLocalKey)
		VALUES (?, ?, ?, NULL, NULL)`,
		"record-type-1",
		"object-1",
		"original",
	); err != nil {
		t.Fatalf("insert mutable RecordType fixture: %v", err)
	}

	tx, cleanupTx, err := BeginPessimisticTx(ctx, db)
	if err != nil {
		t.Fatalf("begin pessimistic transaction: %v", err)
	}
	finished := false
	defer func() {
		if !finished {
			_ = tx.Rollback()
			_ = cleanupTx()
		}
	}()

	var snapshotDescription string
	if err := tx.QueryRowContext(
		ctx,
		`SELECT Description FROM _System_RecordType WHERE Id = ?`,
		"record-type-1",
	).Scan(&snapshotDescription); err != nil {
		t.Fatalf("establish repeatable-read snapshot: %v", err)
	}
	if _, err := db.ExecContext(ctx, `UPDATE _System_RecordType
		SET CatalogNamespaceId = ?, CatalogLocalKey = ?
		WHERE Id = ?`,
		[]byte("namespace"),
		[]byte("local"),
		"record-type-1",
	); err != nil {
		t.Fatalf("commit concurrent authority claim: %v", err)
	}

	txCtx := context.WithValue(ctx, txContextKey{}, tx)
	txCtx = context.WithValue(txCtx, pessimisticTxMarkerKey{}, true)
	repository := NewRecordRepository(db)
	repository.SetSchemaProvider(writeProtectionSchemaProvider{})
	err = repository.Update(
		txCtx,
		constants.TableRecordType,
		"record-type-1",
		models.SObject{constants.FieldSysRecordType_Description: "forbidden"},
	)
	var validationErr *apperrors.ValidationError
	if !errors.As(err, &validationErr) {
		t.Fatalf("concurrent authority claim error = %T %v, want validation error", err, err)
	}
	if err := tx.Rollback(); err != nil {
		t.Fatalf("rollback diagnostic transaction: %v", err)
	}
	if err := cleanupTx(); err != nil {
		t.Fatalf("cleanup diagnostic transaction: %v", err)
	}
	finished = true

	var description string
	if err := db.QueryRowContext(
		ctx,
		`SELECT Description FROM _System_RecordType WHERE Id = ?`,
		"record-type-1",
	).Scan(&description); err != nil {
		t.Fatalf("read protected RecordType fixture: %v", err)
	}
	if description != "original" {
		t.Fatalf("protected RecordType description = %q, want original", description)
	}
}
