package gateway

import (
	"context"
	"testing"
	"time"

	"github.com/tech/sendico/gateway/mntx/storage/model"
)

func TestStrictIsolatedPayoutExecutionMode_BlocksOtherOperationUntilFinalStatus(t *testing.T) {
	mode := newStrictIsolatedPayoutExecutionMode()
	if err := mode.BeforeDispatch(context.Background(), "op-1"); err != nil {
		t.Fatalf("first acquire failed: %v", err)
	}

	waitCtx, waitCancel := context.WithTimeout(context.Background(), time.Second)
	defer waitCancel()
	secondDone := make(chan error, 1)
	go func() {
		secondDone <- mode.BeforeDispatch(waitCtx, "op-2")
	}()

	select {
	case err := <-secondDone:
		t.Fatalf("second operation should be blocked before final status, got err=%v", err)
	case <-time.After(80 * time.Millisecond):
	}

	mode.OnPersistedState("op-1", model.PayoutStatusWaiting)

	select {
	case err := <-secondDone:
		t.Fatalf("second operation should remain blocked on non-final status, got err=%v", err)
	case <-time.After(80 * time.Millisecond):
	}

	mode.OnPersistedState("op-1", model.PayoutStatusSuccess)

	select {
	case err := <-secondDone:
		if err != nil {
			t.Fatalf("second operation should proceed after final status, got err=%v", err)
		}
	case <-time.After(time.Second):
		t.Fatalf("timeout waiting for second operation to proceed")
	}
}

func TestStrictIsolatedPayoutExecutionMode_AllowsSameOperationReentry(t *testing.T) {
	mode := newStrictIsolatedPayoutExecutionMode()
	if err := mode.BeforeDispatch(context.Background(), "op-1"); err != nil {
		t.Fatalf("first acquire failed: %v", err)
	}
	if err := mode.BeforeDispatch(context.Background(), "op-1"); err != nil {
		t.Fatalf("same operation should be re-entrant, got err=%v", err)
	}
}
