package app

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/store/agent"
	"github.com/tidbcloud/AgentTeam/internal/store/message"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
)

// TestReviewFeedbackCreatesListsAndUpdatesThreadMessage exercises the review
// feedback CRUD against a thread-bound review context (the single model only
// supports thread-bound feedback; the legacy channel/DM subjects were removed).
func TestReviewFeedbackCreatesListsAndUpdatesThreadMessage(t *testing.T) {
	t.Parallel()

	ctx := context.Background()
	pool := startAppRollbackDB(t, ctx)
	store := New(pool, Options{})
	now := time.Date(2026, 7, 1, 10, 0, 0, 0, time.UTC)
	fixture := seedAppAdminFixture(t, pool, "review_feedback_thread", now)
	user := model.User{ID: fixture.UserID, Name: "review_feedback_thread", DisplayName: "Reviewer"}
	threadID := openThreadWithReplies(t, ctx, pool, store, fixture, user, fixture.AllChannelID, "review root", nil)
	rc := agent.ReviewContext{ID: "rcx_review_feedback_thread", ThreadID: threadID, DisplayName: "Backend diff"}

	created, delivery, err := store.CreateReviewFeedbackForUser(ctx, user, fixture.WorkspaceID, rc, reviewFeedbackBuildRequest("client-review-thread"))
	require.NoError(t, err)
	require.False(t, delivery.IdempotentReplay)
	require.Equal(t, threadID, created.ChannelID)
	require.Empty(t, created.MessageType)
	require.Equal(t, message.ContributionSourceKindReviewComment, created.Source.Kind)
	require.Equal(t, created.ID, created.Source.RefID)
	require.Equal(t, "Backend diff", created.Source.Label)
	require.Equal(t, message.ContributionSourceKindReviewComment, delivery.Message.Source.Kind)
	require.Equal(t, created.ID, delivery.Message.Source.RefID)
	require.Equal(t, "Backend diff", delivery.Message.Source.Label)
	payload, ok, err := message.ReviewFeedbackPayloadFromMetadata(created.Metadata)
	require.NoError(t, err)
	require.True(t, ok)
	require.Equal(t, rc.ID, payload.ReviewContextID)
	require.Len(t, payload.Items, 1)

	replayed, replayDelivery, err := store.CreateReviewFeedbackForUser(ctx, user, fixture.WorkspaceID, rc, reviewFeedbackBuildRequest("client-review-thread"))
	require.NoError(t, err)
	require.True(t, replayDelivery.IdempotentReplay)
	require.Equal(t, created.ID, replayed.ID)

	messages, err := store.ListReviewFeedbackForUser(ctx, fixture.UserID, fixture.WorkspaceID, rc, 10)
	require.NoError(t, err)
	require.Len(t, messages, 1)
	require.Equal(t, created.ID, messages[0].ID)

	updated, err := store.SetReviewFeedbackItemStatusForUser(ctx, user, fixture.WorkspaceID, rc, created.ID, payload.Items[0].ID, message.ReviewFeedbackStatusResolved)
	require.NoError(t, err)
	require.Equal(t, created.Content, updated.Content)
	updatedPayload, ok, err := message.ReviewFeedbackPayloadFromMetadata(updated.Metadata)
	require.NoError(t, err)
	require.True(t, ok)
	require.Equal(t, message.ReviewFeedbackStatusResolved, updatedPayload.Items[0].Status)
	require.Equal(t, fixture.MemberID, updatedPayload.Items[0].ResolvedByMemberID)
}

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

	ctx := context.Background()
	pool := startAppRollbackDB(t, ctx)
	store := New(pool, Options{})
	now := time.Date(2026, 7, 1, 10, 5, 0, 0, time.UTC)
	fixture := seedAppAdminFixture(t, pool, "review_feedback_routes", now)
	user := model.User{ID: fixture.UserID, Name: "review_feedback_routes", DisplayName: "Reviewer"}

	threadID := openThreadWithReplies(t, ctx, pool, store, fixture, user, fixture.AllChannelID, "review root", nil)
	rc := agent.ReviewContext{ID: "rcx_review_feedback_thread", ThreadID: threadID}
	threadMessage, _, err := store.CreateReviewFeedbackForUser(ctx, user, fixture.WorkspaceID, rc, reviewFeedbackBuildRequest("client-review-thread"))
	require.NoError(t, err)
	require.Equal(t, threadID, threadMessage.ChannelID)
	requireScopeMessageAndSingleFanout(t, pool, threadMessage.ID, fixture.WorkspaceID, threadID)
}

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

	ctx := context.Background()
	pool := startAppRollbackDB(t, ctx)
	store := New(pool, Options{})
	now := time.Date(2026, 7, 1, 10, 10, 0, 0, time.UTC)
	fixture := seedAppAdminFixture(t, pool, "review_feedback_source_agent", now)
	user := model.User{ID: fixture.UserID, Name: "review_feedback_source_agent", DisplayName: "Reviewer"}

	const (
		machineID     = "mach_review_feedback_source_agent"
		agentID       = "agt_review_feedback_source_agent"
		agentMemberID = "mem_agent_review_feedback_source"
		agentName     = "review-feedback-source-agent"
	)
	seedAppAgentParticipant(t, pool, fixture.WorkspaceID, fixture.UserID, fixture.MemberID, fixture.AllChannelID, machineID, agentID, agentMemberID, agentName, now)

	threadID := openThreadWithReplies(t, ctx, pool, store, fixture, user, fixture.AllChannelID, "review source root", nil)
	rc := agent.ReviewContext{ID: "rcx_review_feedback_source_thread", ThreadID: threadID, SourceAgentID: agentID}
	_, delivery, err := store.CreateReviewFeedbackForUser(ctx, user, fixture.WorkspaceID, rc, reviewFeedbackBuildRequest("client-review-source-thread"))
	require.NoError(t, err)
	require.Equal(t, message.AgentDeliveryReasonDirectMention, agentDeliveryReasonsByMember(delivery.Recipients)[agentMemberID])
	require.Equal(t, message.AgentDeliveryReasonDirectMention, agentDeliveryReasonsByMember(delivery.WakeRecipients)[agentMemberID])
}

func reviewFeedbackBuildRequest(clientMessageID string) message.ReviewFeedbackBuildRequest {
	return message.ReviewFeedbackBuildRequest{
		ClientMessageID: clientMessageID,
		Summary:         "Please address these review comments.",
		Items: []message.ReviewFeedbackItemInput{{
			Path:   "internal/api/review.go",
			Body:   "Please add a permission check here.",
			Anchor: map[string]any{"line": 12},
		}},
	}
}
