//go:build integration

package steme

import (
	"context"
	"testing"
	"time"
)

// Integration tests for Query operations including lenses and filtering.

// TestIntegration_Query_WithLens tests querying with different lenses.
func TestIntegration_Query_WithLens(t *testing.T) {
	client := getTestClient(t)
	ctx := context.Background()

	// Create a unique subject for this test
	subject := uniqueSubject("IntegrationTest_Lens")
	predicate := "has_revenue"

	// Create multiple assertions with different values
	assertions := []struct {
		value      float64
		confidence float64
	}{
		{100.0, 0.9},
		{105.0, 0.95},
		{100.0, 0.85}, // Duplicate value to test consensus
	}

	for i, a := range assertions {
		assertion := NewAssertion(subject, predicate).
			WithNumber(a.value).
			WithConfidence(a.confidence).
			WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000").
			Build()

		hash, err := client.Assert(ctx, assertion)
		if err != nil {
			t.Fatalf("Assert(%d) failed: %v", i, err)
		}

		t.Logf("Created assertion %d with hash: %s (value: %.1f, confidence: %.2f)",
			i, hash, a.value, a.confidence)
	}

	// Small delay for indexing
	time.Sleep(100 * time.Millisecond)

	// Test different lenses
	lensTests := []struct {
		name string
		lens Lens
	}{
		{"Recency", LensRecency},
		{"Consensus", LensConsensus},
		{"Authority", LensAuthority},
	}

	for _, tt := range lensTests {
		t.Run(tt.name, func(t *testing.T) {
			params := NewQuery().
				WithSubject(subject).
				WithPredicate(predicate).
				WithLens(tt.lens).
				Build()

			result, err := client.Query(ctx, params)
			if err != nil {
				t.Fatalf("Query() with lens %s failed: %v", tt.lens, err)
			}

			if result.TotalCount == 0 {
				t.Errorf("Query() with lens %s returned no results", tt.lens)
			}

			t.Logf("Lens %s returned %d results", tt.lens, result.TotalCount)

			// Verify all results match our subject/predicate
			for _, a := range result.Assertions {
				if a.Subject != subject {
					t.Errorf("Result has wrong subject: %s, want %s", a.Subject, subject)
				}

				if a.Predicate != predicate {
					t.Errorf("Result has wrong predicate: %s, want %s", a.Predicate, predicate)
				}
			}
		})
	}
}

// TestIntegration_Query_NotFound tests querying for non-existent data.
func TestIntegration_Query_NotFound(t *testing.T) {
	client := getTestClient(t)
	ctx := context.Background()

	// Query for a subject that definitely doesn't exist
	subject := uniqueSubject("IntegrationTest_NonExistent")

	params := NewQuery().
		WithSubject(subject).
		WithPredicate("does_not_exist").
		Build()

	result, err := client.Query(ctx, params)
	if err != nil {
		t.Fatalf("Query() failed: %v", err)
	}

	if result.TotalCount != 0 {
		t.Errorf("Query() for non-existent data returned %d results, want 0", result.TotalCount)
	}

	if len(result.Assertions) != 0 {
		t.Errorf("Query() for non-existent data returned %d assertions, want 0", len(result.Assertions))
	}

	if result.HasMore {
		t.Error("Query() for non-existent data claims HasMore = true")
	}
}

// TestIntegration_Query_Limit tests the limit parameter.
func TestIntegration_Query_Limit(t *testing.T) {
	client := getTestClient(t)
	ctx := context.Background()

	subject := uniqueSubject("IntegrationTest_Limit")
	predicate := "has_index"

	// Create 5 assertions
	const numAssertions = 5
	for i := 0; i < numAssertions; i++ {
		assertion := NewAssertion(subject, predicate).
			WithNumber(float64(i)).
			WithConfidence(0.9).
			WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000").
			Build()

		_, err := client.Assert(ctx, assertion)
		if err != nil {
			t.Fatalf("Assert(%d) failed: %v", i, err)
		}
	}

	// Small delay for indexing
	time.Sleep(100 * time.Millisecond)

	// Query with limit of 2
	params := NewQuery().
		WithSubject(subject).
		WithPredicate(predicate).
		WithLimit(2).
		Build()

	result, err := client.Query(ctx, params)
	if err != nil {
		t.Fatalf("Query() failed: %v", err)
	}

	if len(result.Assertions) > 2 {
		t.Errorf("Query() with limit=2 returned %d results, want at most 2", len(result.Assertions))
	}

	if result.TotalCount > 2 && !result.HasMore {
		t.Error("Query() should indicate HasMore when total > limit")
	}
}
