package rewindplan

import (
	"testing"

	"github.com/stretchr/testify/require"
)

func TestPlanSuffixBoundariesUseScopeID(t *testing.T) {
	plan := Plan{
		ScopeID:              " scp_primary ",
		BroadcastScopeID:     " scp_broadcast ",
		ReplyThreadScopeID:   " scp_reply ",
		ReplyParentMessageID: " msg_parent ",
		TargetMessageID:      "msg_target",
		TargetSeq:            7,
		SuffixMessageIDs: []string{
			"msg_target",
			"msg_tail",
		},
		CascadeReplyThreads: []CascadeReplyThread{{
			ScopeID:         " scp_child ",
			ParentMessageID: " msg_tail ",
			MessageIDs:      []string{"msg_child"},
		}},
	}

	boundaries := plan.SuffixBoundaries()

	require.Len(t, boundaries, 2)
	require.Equal(t, SuffixBoundaryPrimary, boundaries[0].Role)
	require.Equal(t, "scp_primary", boundaries[0].Normalize().ScopeID)
	require.Equal(t, int64(7), boundaries[0].FromSeq)
	require.Equal(t, []string{"msg_target", "msg_tail"}, boundaries[0].Normalize().MessageIDs)
	require.Equal(t, SuffixBoundaryCascadeReplyThread, boundaries[1].Role)
	require.Equal(t, "scp_child", boundaries[1].Normalize().ScopeID)
	require.Equal(t, int64(1), boundaries[1].FromSeq)
	require.NoError(t, plan.ValidateSuffixBoundaries())
	require.Equal(t, []string{"scp_primary", "scp_child"}, plan.RewindScopeIDs())
	require.Equal(t, "scp_primary", plan.OperationScopeID())
	require.Equal(t, "scp_broadcast", plan.RealtimeBroadcastScopeID())
	require.Equal(t, "scp_reply", plan.ReplyThreadStateScopeID())
	require.Equal(t, "msg_parent", plan.ReplyThreadParentMessageID())
}

func TestPlanScopeAccessorsUseTypedScopeFieldsOnly(t *testing.T) {
	plan := Plan{
		ScopeID:              " scp_primary ",
		BroadcastScopeID:     " scp_broadcast ",
		ReplyThreadScopeID:   " scp_reply ",
		ReplyParentMessageID: " msg_parent ",
	}
	require.Equal(t, "scp_primary", plan.RewindScopeID())
	require.Equal(t, "scp_primary", plan.OperationScopeID())
	require.Equal(t, "scp_broadcast", plan.RealtimeBroadcastScopeID())
	require.Equal(t, "scp_reply", plan.ReplyThreadStateScopeID())
	require.Equal(t, "msg_parent", plan.ReplyThreadParentMessageID())
	require.Equal(t, []string{"scp_primary"}, plan.RewindScopeIDs())

	thread := CascadeReplyThread{ScopeID: " scp_child "}
	require.Equal(t, "scp_child", thread.CascadeScopeID())
}

func TestSuffixBoundaryValidationRejectsAmbiguousDeletion(t *testing.T) {
	err := (SuffixBoundary{
		Role:            SuffixBoundaryPrimary,
		ScopeID:         "scp_primary",
		TargetMessageID: "msg_target",
		FromSeq:         7,
		MessageIDs:      []string{"msg_later"},
	}).Validate()
	require.ErrorContains(t, err, "must start at target message")

	err = (SuffixBoundary{
		Role:       SuffixBoundaryCascadeReplyThread,
		ScopeID:    "thr_child",
		FromSeq:    2,
		MessageIDs: []string{"msg_child"},
	}).Validate()
	require.ErrorContains(t, err, "parent message id is required")
}

func TestOperationStatusContract(t *testing.T) {
	require.True(t, OperationStatusPreparing.Valid())
	require.True(t, OperationStatusRepairRequired.Valid())
	require.False(t, OperationStatus("unknown").Valid())
	require.Equal(t, []OperationStatus{OperationStatusPreparing}, ActiveRewindOperationStatuses())
}
