package kb

import (
	"strings"
	"testing"
	"time"

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

func seedPublicationSnapshot(t *testing.T, store *Store, now time.Time) PublicationSnapshotResult {
	t.Helper()
	_, err := store.CreateKnowledgeBase(t.Context(), KnowledgeBase{
		ID: "kb_1", WorkspaceID: "ws_1", GroupID: "group_1", Name: "Review me",
		Description: "Frozen description", PublicationState: "draft", WorkingRevision: "kbr_1",
		IsActive: true, RetrievalPolicy: "{}", SourceCollectionState: "{}",
		CreatedBy: "member", UpdatedBy: "member", CreatedAt: now, UpdatedAt: now,
	})
	require.NoError(t, err)
	_, err = store.CreateKnowledgeBaseSetupSession(t.Context(), KnowledgeBaseSetupSession{
		ID: "kbs_1", WorkspaceID: "ws_1", KnowledgeBaseID: "kb_1", Mode: "create_draft",
		ActiveStep: "review", WorkingRevision: "kbr_1", Version: 1,
		CreatedBy: "member", UpdatedBy: "member", CreatedAt: now, UpdatedAt: now,
	})
	require.NoError(t, err)
	_, err = store.CreateSource(t.Context(), Source{
		ID: "src_1", WorkspaceID: "ws_1", KnowledgeBaseID: "kb_1", SourceType: "codebase",
		Name: "AgentTeam", Status: "ready", SyncStatus: "ready", IndexStatus: "ready", Config: "{}",
		CreatedBy: "member", UpdatedBy: "member", CreatedAt: now, UpdatedAt: now,
	})
	require.NoError(t, err)
	_, err = store.CreateSourceRevision(t.Context(), SourceRevision{
		ID: "rev_1", WorkspaceID: "ws_1", KnowledgeBaseID: "kb_1", SourceID: "src_1",
		SourceCommitSHA: "source-sha", IsCurrent: true, CreatedAt: now, UpdatedAt: now,
	})
	require.NoError(t, err)
	for _, kind := range []string{"wiki", "dashboard"} {
		_, err = store.UpsertKnowledgeBaseSetupSourceArtifact(t.Context(), KnowledgeBaseSetupSourceArtifact{
			ID: "artifact_" + kind, WorkspaceID: "ws_1", KnowledgeBaseID: "kb_1", SourceID: "src_1",
			Kind: kind, State: "skipped", UpdatedBy: "member", CreatedAt: now, UpdatedAt: now,
		})
		require.NoError(t, err)
	}
	snapshot, err := store.LoadKnowledgeBasePublicationSnapshot(t.Context(), "ws_1", "kb_1", false)
	require.NoError(t, err)
	require.Equal(t, 2, snapshot.SkippedCount)
	return snapshot
}

func publicationRequestFixture(snapshot PublicationSnapshotResult, now time.Time) KnowledgeBasePublicationRequest {
	return KnowledgeBasePublicationRequest{
		ID: "kbpub_1", WorkspaceID: "ws_1", KnowledgeBaseID: "kb_1", WorkingRevision: "kbr_1",
		RequesterID: "member", ApprovalID: "appr_1", ApprovalVersion: 1,
		Status: PublicationRequestStatusPendingApproval, IdempotencyKey: "publish-1",
		PayloadDigest: strings.Repeat("a", 64), ContentDigest: snapshot.Digest,
		SnapshotJSON: string(snapshot.JSON), SourceCount: snapshot.SourceCount,
		SkippedCount: snapshot.SkippedCount, Version: 1, CreatedAt: now, UpdatedAt: now,
	}
}

func TestResolveKnowledgeBasePublicationAtomicallyPublishesFrozenRevision(t *testing.T) {
	store := newTestStore(t)
	now := time.Date(2026, 8, 9, 10, 0, 0, 0, time.UTC)
	snapshot := seedPublicationSnapshot(t, store, now)
	request, created, err := store.CreateKnowledgeBasePublicationRequest(t.Context(), publicationRequestFixture(snapshot, now), now)
	require.NoError(t, err)
	require.True(t, created)

	resolved, applied, err := store.ResolveKnowledgeBasePublication(t.Context(), ResolveKnowledgeBasePublicationParams{
		WorkspaceID: "ws_1", ApprovalID: request.ApprovalID, ApprovalVersion: 2,
		ActorID: "admin", ClientDecisionID: "decision-1", Decision: GenerationDecisionApproved,
		AuthorizationValid: true, Now: now.Add(time.Minute),
	})
	require.NoError(t, err)
	require.True(t, applied)
	require.Equal(t, PublicationRequestStatusPublished, resolved.Status)

	base, err := store.GetKnowledgeBase(t.Context(), "ws_1", "kb_1")
	require.NoError(t, err)
	require.Equal(t, "official", base.PublicationState)
	require.Equal(t, "kbr_1", base.PublishedRevision)
	require.Empty(t, base.WorkingRevision)
	require.NotNil(t, base.PublishedAt)
	session, err := store.GetKnowledgeBaseSetupSession(t.Context(), "ws_1", "kb_1")
	require.NoError(t, err)
	require.Equal(t, "kbr_1", session.PublishedRevision)
	require.Equal(t, request.SnapshotJSON, session.PublishedSnapshotJSON)
	require.Equal(t, request.SnapshotJSON, session.WorkingSnapshotJSON)
	require.NotNil(t, session.CompletedAt)
	require.EqualValues(t, 2, session.Version)

	replayed, applied, err := store.ResolveKnowledgeBasePublication(t.Context(), ResolveKnowledgeBasePublicationParams{
		WorkspaceID: "ws_1", ApprovalID: request.ApprovalID, ApprovalVersion: 2,
		ActorID: "admin", ClientDecisionID: "decision-1", Decision: GenerationDecisionApproved,
		AuthorizationValid: true, Now: now.Add(time.Minute),
	})
	require.NoError(t, err)
	require.False(t, applied)
	require.Equal(t, resolved.ID, replayed.ID)
}

func TestResolveKnowledgeBasePublicationMarksConcurrentEditStale(t *testing.T) {
	store := newTestStore(t)
	now := time.Date(2026, 8, 9, 10, 0, 0, 0, time.UTC)
	snapshot := seedPublicationSnapshot(t, store, now)
	request, _, err := store.CreateKnowledgeBasePublicationRequest(t.Context(), publicationRequestFixture(snapshot, now), now)
	require.NoError(t, err)
	require.NoError(t, store.DB().Model(&KnowledgeBase{}).Where("workspace_id = ? AND id = ?", "ws_1", "kb_1").Update("description", "edited after submit").Error)

	resolved, applied, err := store.ResolveKnowledgeBasePublication(t.Context(), ResolveKnowledgeBasePublicationParams{
		WorkspaceID: "ws_1", ApprovalID: request.ApprovalID, ApprovalVersion: 2,
		ActorID: "admin", ClientDecisionID: "decision-stale", Decision: GenerationDecisionApproved,
		AuthorizationValid: true, Now: now.Add(time.Minute),
	})
	require.NoError(t, err)
	require.True(t, applied)
	require.Equal(t, PublicationRequestStatusStale, resolved.Status)

	base, err := store.GetKnowledgeBase(t.Context(), "ws_1", "kb_1")
	require.NoError(t, err)
	require.Equal(t, "draft", base.PublicationState)
	require.Empty(t, base.PublishedRevision)
}
