package content

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

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/AgentTeam/internal/contentpayload"
	store "github.com/tidbcloud/AgentTeam/internal/store/content"
)

type recordingVersionConsumer struct {
	events []VersionCommittedEvent
	err    error
}

func (consumer *recordingVersionConsumer) ConsumeVersionCommitted(_ context.Context, event VersionCommittedEvent) error {
	consumer.events = append(consumer.events, event)
	return consumer.err
}

func TestOutboxWorkerDeliversAndRetriesBoundedBatch(t *testing.T) {
	service, database := newServiceTest(t)
	ctx := context.Background()
	content, err := service.CreateContent(ctx, CreateContentRequest{WorkspaceID: "wsp_1", Domain: "skill", BindingKey: "skill_1", Model: store.ModelTree, Actor: "usr_1"})
	require.NoError(t, err)
	committed, err := service.CommitVersion(ctx, CommitVersionRequest{
		WorkspaceID: "wsp_1", ContentID: content.ID, ExpectedGeneration: 1,
		Actor: "usr_1", Model: store.ModelTree,
		Files: []contentpayload.File{{Path: "SKILL.md", Size: 5, Content: bytes.NewBufferString("hello")}},
	})
	require.NoError(t, err)

	consumer := &recordingVersionConsumer{}
	worker, err := NewOutboxWorker(store.New(database), consumer, "worker-1", time.Minute)
	require.NoError(t, err)
	now := time.Date(2026, 8, 10, 20, 1, 0, 0, time.UTC)
	worker.now = func() time.Time { return now }
	result, err := worker.RunOnce(ctx, 10)
	require.NoError(t, err)
	require.Equal(t, OutboxWorkerResult{Leased: 1, Delivered: 1}, result)
	require.Equal(t, committed.Version.ID, consumer.events[0].VersionID)

	var delivered store.Outbox
	require.NoError(t, database.Where("version_id = ?", committed.Version.ID).First(&delivered).Error)
	require.Equal(t, store.OutboxStatusDelivered, delivered.Status)

	second, err := service.CommitVersion(ctx, CommitVersionRequest{
		WorkspaceID: "wsp_1", ContentID: content.ID, ExpectedHeadVersionID: committed.Version.ID, ExpectedGeneration: 1,
		Actor: "usr_1", Model: store.ModelTree,
		Files: []contentpayload.File{{Path: "SKILL.md", Size: 6, Content: bytes.NewBufferString("hello2")}},
	})
	require.NoError(t, err)
	consumer.err = errors.New("projection unavailable")
	result, err = worker.RunOnce(ctx, 10)
	require.NoError(t, err)
	require.Equal(t, OutboxWorkerResult{Leased: 1, Retried: 1}, result)
	var retried store.Outbox
	require.NoError(t, database.Where("version_id = ?", second.Version.ID).First(&retried).Error)
	require.Equal(t, 1, retried.Attempts)
	require.True(t, retried.NextAttemptAt.After(now))
	require.Empty(t, retried.LeaseOwner)
}
