package persistence

import (
	"context"
	"errors"
	"testing"

	database "github.com/nexuscrm/db"
	"github.com/nexuscrm/kernel/pkg/schemacatalog"
)

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

	definitions, err := schemacatalog.ManagedTableDefinitions()
	if err != nil {
		t.Fatal(err)
	}
	schemaRepository := NewSchemaRepository(db, nil)
	for _, definition := range definitions {
		if definition.TableName == PermissionStateVersionTable {
			if err := schemaRepository.CreatePhysicalTable(context.Background(), definition); err != nil {
				t.Fatalf("CreatePhysicalTable(%s): %v", definition.TableName, err)
			}
		}
	}

	stateRepository := newPermissionStateRepositoryForTest(t, db, permissionStateLineage)
	initial, err := stateRepository.EnsureInitialized(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	enforced, err := stateRepository.PromoteToEnforced(
		context.Background(),
		initial.Version,
	)
	if err != nil {
		t.Fatal(err)
	}
	assertPermissionState(
		t,
		enforced,
		permissionStateLineage,
		2,
		PermissionStateEnforcedMode,
	)

	retried, err := stateRepository.PromoteToEnforced(
		context.Background(),
		initial.Version,
	)
	if err != nil {
		t.Fatal(err)
	}
	assertPermissionState(
		t,
		retried,
		permissionStateLineage,
		2,
		PermissionStateEnforcedMode,
	)

	transactions := NewTransactionManager(database.NewConnectionFromDB(db))
	authority := newPermissionStateAuthorityForTest(t, transactions)
	if err := transactions.WithPessimisticTransaction(
		context.Background(),
		func(ctx context.Context) error {
			_, _, err := authority.AdvanceIfChanged(ctx, true)
			return err
		},
	); err != nil {
		t.Fatal(err)
	}
	if _, err := stateRepository.PromoteToEnforced(
		context.Background(),
		initial.Version,
	); !errors.Is(err, ErrPermissionStateActivationConflict) {
		t.Fatalf("stale retry error = %v, want activation conflict", err)
	}
	current, err := stateRepository.CheckReady(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	assertPermissionState(
		t,
		current,
		permissionStateLineage,
		3,
		PermissionStateEnforcedMode,
	)
}
