// Package main demonstrates basic StemeDB SDK usage.
//
// This example shows:
//   - Creating a signer (keypair)
//   - Building an assertion with the fluent API
//   - Submitting to StemeDB (auto-signed)
//   - Understanding eventual consistency
//   - Querying with a lens
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/orchard9/stemedb-go/steme"
)

func main() {
	// 1. Generate a new keypair
	//
	// In production, you'd load this from environment or key management.
	// For this example, we generate a new one each run.
	signer, err := steme.GenerateSigner()
	if err != nil {
		log.Fatalf("Failed to generate signer: %v", err)
	}

	fmt.Printf("Agent ID (public key): %s\n", signer.PublicKey())
	fmt.Printf("Seed (save this!): %s\n\n", signer.Seed())

	// 2. Create a StemeDB client
	//
	// The client automatically signs all assertions using the signer.
	client := steme.NewClient("http://localhost:18180", signer)

	// 3. Build an assertion with the fluent API
	//
	// This asserts: "Tesla_Inc has_revenue 96.7 (billion USD)"
	// with 95% confidence, marked as Approved, sourced from Clinical evidence.
	assertion := steme.NewAssertion("Tesla_Inc", "has_revenue").
		WithNumber(96.7).
		WithConfidence(0.95).
		WithLifecycle(steme.LifecycleApproved).
		WithSourceClass(steme.SourceClassClinical).
		WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000").
		Build()

	// 4. Submit to StemeDB
	//
	// The client automatically:
	//   - Signs the assertion with your private key
	//   - Adds a timestamp
	//   - POSTs to /v1/assert
	//   - Returns the content-addressed hash
	hash, err := client.Assert(context.Background(), assertion)
	if err != nil {
		log.Fatalf("Failed to assert: %v", err)
	}

	fmt.Printf("✓ Created assertion: %s\n\n", hash)

	// 5. Understanding Eventual Consistency
	//
	// StemeDB is eventually consistent by design. When Assert() returns,
	// the assertion is durably written to the Write-Ahead Log (WAL), but
	// the background IngestWorker hasn't necessarily indexed it yet.
	//
	// This is intentional for high write throughput. For production code:
	//   - Design workflows that tolerate async (recommended for agents)
	//   - Use polling with timeout when read-after-write is needed
	//   - Check health.AssertionsCount to monitor ingestion progress
	//
	// Here we demonstrate polling until the assertion is queryable:

	params := steme.NewQuery().
		WithSubject("Tesla_Inc").
		WithPredicate("has_revenue").
		WithLens(steme.LensConsensus).
		Build()

	fmt.Println("Waiting for ingestion...")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	var result *steme.QueryResult
	for {
		result, err = client.Query(ctx, params)
		if err != nil {
			log.Fatalf("Failed to query: %v", err)
		}
		if result.TotalCount > 0 {
			fmt.Println("✓ Assertion indexed")
			fmt.Println()
			break
		}
		select {
		case <-ctx.Done():
			// Timeout - assertion created but not yet indexed
			// This is normal; in production, design for eventual consistency
			fmt.Println("Note: Assertion created but not yet indexed")
			fmt.Println("This is expected - StemeDB is eventually consistent")
			fmt.Println()
			goto showResults
		case <-time.After(100 * time.Millisecond):
			// Continue polling
		}
	}

showResults:
	// 6. Display query results
	fmt.Printf("Query Results:\n")
	fmt.Printf("  Total: %d assertions\n", result.TotalCount)
	fmt.Printf("  Has more: %v\n\n", result.HasMore)

	for i, a := range result.Assertions {
		fmt.Printf("Assertion #%d:\n", i+1)
		fmt.Printf("  Hash: %s\n", a.Hash)
		fmt.Printf("  Subject: %s\n", a.Subject)
		fmt.Printf("  Predicate: %s\n", a.Predicate)
		fmt.Printf("  Object: %v (%s)\n", a.Object.Value, a.Object.Type)
		fmt.Printf("  Confidence: %.2f\n", a.Confidence)
		fmt.Printf("  Lifecycle: %s\n", a.Lifecycle)
		fmt.Printf("  Source Class: %s\n", a.SourceClass)
		fmt.Printf("  Signatures: %d agents\n", len(a.Signatures))
		fmt.Printf("\n")
	}

	// 7. Health check
	health, err := client.Health(context.Background())
	if err != nil {
		log.Fatalf("Failed health check: %v", err)
	}

	fmt.Printf("StemeDB Health:\n")
	fmt.Printf("  Status: %s\n", health.Status)
	fmt.Printf("  Version: %s\n", health.Version)
	fmt.Printf("  Assertions: %d\n", health.AssertionsCount)
}
