package server

import (
	"context"
	"reflect"
	"testing"

	"github.com/tidbcloud/AgentTeam/internal/store/taskboard"
	"github.com/tidbcloud/AgentTeam/internal/unread"
)

func TestTaskUnreadRuntimeBridgeSuppressesDoneTaskState(t *testing.T) {
	t.Parallel()

	runtime := &recordingTaskUnreadRuntime{
		invalidationDeltas: []unread.UnreadDelta{{
			WorkspaceID:  "workspace_1",
			UserID:       "user_1",
			MemberID:     "member_1",
			ScopeID:      "task_scope_1",
			ServingState: unread.ServingStateStale,
		}},
	}
	deltas := &recordingTaskUnreadDeltaSink{}
	bridge := newTaskUnreadRuntimeBridge(runtime, deltas)

	bridge.HandleTaskChange(context.Background(), taskboard.TaskChangeEvent{
		EventType: taskboard.TaskChangeUpdated,
		Context:   taskboard.NewUserServiceContext("workspace_1", "user_1", "Alice"),
		Task: taskboard.Task{
			ID:          "task_1",
			TaskScopeID: "task_scope_1",
			Status:      string(taskboard.StatusDone),
		},
	})
	bridge.HandleTaskChange(context.Background(), taskboard.TaskChangeEvent{
		EventType: taskboard.TaskChangeUpdated,
		Context:   taskboard.NewUserServiceContext("workspace_1", "user_1", "Alice"),
		Task: taskboard.Task{
			ID:          "task_2",
			TaskScopeID: "task_scope_2",
			Status:      string(taskboard.StatusInProgress),
		},
	})

	wantInvalidations := []unread.ScopeInvalidated{{
		WorkspaceID: "workspace_1",
		ScopeID:     "task_scope_1",
		Reason:      "task_done",
	}}
	if !reflect.DeepEqual(runtime.invalidationsWithDeltas, wantInvalidations) {
		t.Fatalf("invalidations = %#v, want %#v", runtime.invalidationsWithDeltas, wantInvalidations)
	}
	if len(deltas.items) != 1 || deltas.items[0].ScopeID != "task_scope_1" || deltas.items[0].HasUnread {
		t.Fatalf("emitted deltas = %#v, want one zero unread suppression delta", deltas.items)
	}
}

type recordingTaskUnreadRuntime struct {
	invalidations           []unread.ScopeInvalidated
	invalidationsWithDeltas []unread.ScopeInvalidated
	invalidationDeltas      []unread.UnreadDelta
}

func (runtime *recordingTaskUnreadRuntime) ApplyScopeInvalidated(event unread.ScopeInvalidated) error {
	runtime.invalidations = append(runtime.invalidations, event)
	return nil
}

func (runtime *recordingTaskUnreadRuntime) ApplyScopeInvalidatedWithDeltas(event unread.ScopeInvalidated) ([]unread.UnreadDelta, error) {
	runtime.invalidationsWithDeltas = append(runtime.invalidationsWithDeltas, event)
	return append([]unread.UnreadDelta(nil), runtime.invalidationDeltas...), nil
}

type recordingTaskUnreadDeltaSink struct {
	items []unread.UnreadDelta
}

func (sink *recordingTaskUnreadDeltaSink) EmitUnreadUpdated(_ string, delta unread.UnreadDelta) {
	sink.items = append(sink.items, delta)
}
