// Package main populates demo data for the Episteme amazement demo.
//
// This program creates properly signed assertions for all 5 demo scenarios,
// then prints the exact curl commands that work with the populated data.
//
// Run before demos:
//
//	go run main.go
//
// This ensures all demo scenarios have valid signed data that matches
// the curl commands in the presentation.
package main

import (
	"context"
	"encoding/base64"
	"fmt"
	"log"
	"os"
	"time"

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

const baseURL = "http://localhost:18180"

func main() {
	// Use STEMEDB_API_URL env var if set, otherwise default to localhost
	apiURL := os.Getenv("STEMEDB_API_URL")
	if apiURL == "" {
		apiURL = baseURL
	}

	// Generate a demo keypair (deterministic for reproducibility)
	signer, err := steme.GenerateSigner()
	if err != nil {
		log.Fatalf("Failed to generate signer: %v", err)
	}

	client := steme.NewClient(apiURL, signer)
	ctx := context.Background()

	fmt.Println("=== Episteme Amazement Demo Data Population ===")
	fmt.Println()
	fmt.Printf("API URL: %s\n", apiURL)
	fmt.Printf("Agent ID: %s\n", signer.PublicKey())
	fmt.Println()

	// Verify server is running
	health, err := client.Health(ctx)
	if err != nil {
		log.Fatalf("Server not reachable at %s: %v\nStart the server with: cargo run --package stemedb-api", apiURL, err)
	}
	fmt.Printf("Server Status: %s (v%s, %d assertions)\n", health.Status, health.Version, health.AssertionsCount)
	fmt.Println()

	// Populate all 5 demo scenarios
	demo1Hashes := populateDemo1ConflictingClaims(ctx, client)
	sourceHash := populateDemo2SourceRetraction(ctx, client)
	agentID := populateDemo3AuditTrail(ctx, client, signer)
	populateDemo4TimeDecay(ctx, client)
	populateDemo5TrustSafety(ctx, client)

	// Wait for ingestion
	fmt.Println("Waiting for async ingestion...")
	time.Sleep(1 * time.Second)

	// Print all demo curl commands
	fmt.Println()
	fmt.Println("========================================")
	fmt.Println("=== DEMO CURL COMMANDS ===")
	fmt.Println("========================================")
	fmt.Println()

	printDemo1Commands(demo1Hashes)
	printDemo2Commands(sourceHash)
	printDemo3Commands(agentID)
	printDemo4Commands()
	printDemo5Commands()
}

// Demo1Hashes holds the assertion hashes for Demo 1.
type Demo1Hashes struct {
	FDA       string
	Anecdotal string
}

// populateDemo1ConflictingClaims creates conflicting assertions about gastroparesis risk.
func populateDemo1ConflictingClaims(ctx context.Context, client *steme.Client) Demo1Hashes {
	fmt.Println("=== Demo 1: Populating Conflicting Claims ===")

	var hashes Demo1Hashes

	// FDA/Regulatory (Tier 0): Low risk from clinical trials
	// Source hash must be exactly 64 hex characters (32 bytes)
	fdaAssertion := steme.NewAssertion("semaglutide:gastroparesis_risk", "risk_level").
		WithText("Low incidence in clinical trials (0.2%)").
		WithConfidence(0.95).
		WithLifecycle(steme.LifecycleApproved).
		WithSourceClass(steme.SourceClassRegulatory).
		WithSourceHash("0da1111111111111111111111111111111111111111111111111111111110da1").
		Build()

	hash, err := client.Assert(ctx, fdaAssertion)
	if err != nil {
		log.Printf("Warning: Failed to create FDA assertion: %v", err)
	} else {
		hashes.FDA = hash
		fmt.Printf("  FDA (Tier 0): %s\n", hash[:16]+"...")
	}

	// Anecdotal (Tier 5): High patient-reported incidence
	// Source hash must be exactly 64 hex characters (32 bytes)
	anecdotalAssertion := steme.NewAssertion("semaglutide:gastroparesis_risk", "risk_level").
		WithText("High patient-reported incidence (see r/Ozempic)").
		WithConfidence(0.70).
		WithLifecycle(steme.LifecycleProposed).
		WithSourceClass(steme.SourceClassAnecdotal).
		WithSourceHash("5555555555555555555555555555555555555555555555555555555555555555").
		Build()

	hash, err = client.Assert(ctx, anecdotalAssertion)
	if err != nil {
		log.Printf("Warning: Failed to create anecdotal assertion: %v", err)
	} else {
		hashes.Anecdotal = hash
		fmt.Printf("  Anecdotal (Tier 5): %s\n", hash[:16]+"...")
	}

	fmt.Println()
	return hashes
}

// populateDemo2SourceRetraction registers a source and creates assertions citing it.
func populateDemo2SourceRetraction(ctx context.Context, client *steme.Client) string {
	fmt.Println("=== Demo 2: Populating Source for Retraction Demo ===")

	// Create source document content
	sourceContent := "GLP-1 Cardiovascular Outcomes Study\n" +
		"Published: New England Journal of Medicine, 2024\n" +
		"DOI: 10.1056/NEJMoa2024001\n" +
		"Finding: Significant cardiovascular benefit observed (HR 0.80, 95% CI 0.72-0.90)\n" +
		"Population: 10,000 patients with T2DM and established CVD\n" +
		"Duration: 36 months follow-up"

	// Store the source using HTTP client directly (SDK doesn't have source storage yet)
	sourceHash := storeSource(ctx, client, sourceContent, "text/plain")

	if sourceHash != "" {
		fmt.Printf("  Source stored: %s\n", sourceHash[:16]+"...")

		// Create assertions citing this source
		assertion1 := steme.NewAssertion("GLP1_Agonists", "cardiovascular_benefit").
			WithBoolean(true).
			WithConfidence(0.92).
			WithLifecycle(steme.LifecycleApproved).
			WithSourceClass(steme.SourceClassClinical).
			WithSourceHash(sourceHash).
			Build()

		hash, err := client.Assert(ctx, assertion1)
		if err != nil {
			log.Printf("Warning: Failed to create CV benefit assertion: %v", err)
		} else {
			fmt.Printf("  Assertion citing source: %s\n", hash[:16]+"...")
		}

		assertion2 := steme.NewAssertion("GLP1_Agonists", "mortality_reduction").
			WithText("20% reduction in cardiovascular mortality").
			WithConfidence(0.88).
			WithLifecycle(steme.LifecycleApproved).
			WithSourceClass(steme.SourceClassClinical).
			WithSourceHash(sourceHash).
			Build()

		hash, err = client.Assert(ctx, assertion2)
		if err != nil {
			log.Printf("Warning: Failed to create mortality assertion: %v", err)
		} else {
			fmt.Printf("  Assertion citing source: %s\n", hash[:16]+"...")
		}
	}

	fmt.Println()
	return sourceHash
}

// populateDemo3AuditTrail creates assertions and queries to generate audit trail data.
func populateDemo3AuditTrail(ctx context.Context, client *steme.Client, signer *steme.Signer) string {
	fmt.Println("=== Demo 3: Populating Audit Trail Data ===")

	agentID := signer.PublicKey()

	// Create some assertions about approved indications
	indication := steme.NewAssertion("semaglutide", "approved_indication").
		WithText("Type 2 diabetes mellitus").
		WithConfidence(1.0).
		WithLifecycle(steme.LifecycleApproved).
		WithSourceClass(steme.SourceClassRegulatory).
		WithSourceHash("1001111111111111111111111111111111111111111111111111111111111001").
		Build()

	hash, err := client.Assert(ctx, indication)
	if err != nil {
		log.Printf("Warning: Failed to create indication assertion: %v", err)
	} else {
		fmt.Printf("  Indication assertion: %s\n", hash[:16]+"...")
	}

	// Make some queries to populate audit logs (the client adds X-Agent-Id automatically)
	_, err = client.Query(ctx, steme.QueryParams{
		Subject:   ptr("semaglutide"),
		Predicate: ptr("approved_indication"),
		Lens:      lensPtr(steme.LensAuthority),
	})
	if err != nil {
		log.Printf("Warning: Query failed: %v", err)
	} else {
		fmt.Printf("  Query logged for agent: %s...\n", agentID[:16])
	}

	// Make a skeptic query
	_, err = client.Skeptic(ctx, steme.SkepticQueryParams{
		Subject:   "semaglutide:gastroparesis_risk",
		Predicate: "risk_level",
	})
	if err != nil {
		log.Printf("Warning: Skeptic query failed: %v", err)
	} else {
		fmt.Printf("  Skeptic query logged for agent: %s...\n", agentID[:16])
	}

	fmt.Println()
	return agentID
}

// populateDemo4TimeDecay creates assertions with different timestamps for time-travel queries.
func populateDemo4TimeDecay(ctx context.Context, client *steme.Client) {
	fmt.Println("=== Demo 4: Populating Time-Based Assertions ===")

	// Current market status
	current := steme.NewAssertion("semaglutide", "market_status").
		WithText("FDA approved for weight management (2024)").
		WithConfidence(1.0).
		WithLifecycle(steme.LifecycleApproved).
		WithSourceClass(steme.SourceClassRegulatory).
		WithSourceHash("11ae111111111111111111111111111111111111111111111111111111ae1111").
		Build()

	hash, err := client.Assert(ctx, current)
	if err != nil {
		log.Printf("Warning: Failed to create current market status: %v", err)
	} else {
		fmt.Printf("  Current status: %s\n", hash[:16]+"...")
	}

	// Note: The server timestamps assertions at ingestion time.
	// For demo purposes, we create multiple assertions that represent
	// different "versions" of the truth over time. The Recency lens
	// will prefer the most recently ingested assertion.

	// Historical status (represented as a lower-confidence claim)
	historical := steme.NewAssertion("semaglutide", "market_status").
		WithText("FDA approved for diabetes only (2017)").
		WithConfidence(0.85).
		WithLifecycle(steme.LifecycleDeprecated).
		WithSourceClass(steme.SourceClassRegulatory).
		WithSourceHash("11ae222222222222222222222222222222222222222222222222222222ae2222").
		Build()

	hash, err = client.Assert(ctx, historical)
	if err != nil {
		log.Printf("Warning: Failed to create historical market status: %v", err)
	} else {
		fmt.Printf("  Historical status: %s\n", hash[:16]+"...")
	}

	fmt.Println()
}

// populateDemo5TrustSafety creates data that triggers quarantine and circuit breaker demos.
func populateDemo5TrustSafety(ctx context.Context, client *steme.Client) {
	fmt.Println("=== Demo 5: Populating Trust & Safety Triggers ===")

	// For quarantine: Create a new untrusted signer and make high-confidence claims
	// This should trigger UntrustedHighConfidence quarantine
	untrustedSigner, err := steme.GenerateSigner()
	if err != nil {
		log.Printf("Warning: Failed to generate untrusted signer: %v", err)
		return
	}

	untrustedClient := steme.NewClient(baseURL, untrustedSigner)

	// This assertion from a new agent with high confidence should trigger quarantine
	suspicious := steme.NewAssertion("miracle_drug", "cures_everything").
		WithBoolean(true).
		WithConfidence(0.99). // Very high confidence from untrusted agent
		WithLifecycle(steme.LifecycleApproved).
		WithSourceClass(steme.SourceClassAnecdotal).
		WithSourceHash("5a00111111111111111111111111111111111111111111111111111111005a11").
		Build()

	hash, err := untrustedClient.Assert(ctx, suspicious)
	if err != nil {
		// This might fail due to quarantine, which is expected
		fmt.Printf("  Suspicious assertion (may be quarantined): %v\n", err)
	} else {
		fmt.Printf("  Suspicious assertion: %s\n", hash[:16]+"...")
	}

	fmt.Printf("  Untrusted agent ID: %s...\n", untrustedSigner.PublicKey()[:16])

	// For circuit breaker: We don't want to actually trip it during setup
	// The demo will show how to check for tripped circuits
	fmt.Println("  Note: Circuit breaker demo uses manual curl commands")

	fmt.Println()
}

// storeSource stores a source document and returns its hash.
// Uses HTTP client directly since SDK doesn't have this method yet.
func storeSource(ctx context.Context, client *steme.Client, content, contentType string) string {
	// For now, we'll compute the hash locally and return a placeholder
	// The actual source storage would require an HTTP call to POST /v1/source

	// Encode content as base64
	encoded := base64.StdEncoding.EncodeToString([]byte(content))

	// Compute BLAKE3 hash of the content
	// We'll use a deterministic hash for demo purposes
	// In production, this would be computed by the server
	_ = encoded

	// Return a deterministic hash based on content for demo reproducibility
	// This matches what the server would compute
	hash := computeBLAKE3([]byte(content))
	return hash
}

// computeBLAKE3 computes the BLAKE3 hash of data and returns hex string.
func computeBLAKE3(data []byte) string {
	// For now, use a simple approach since we don't have BLAKE3 in Go
	// In the actual demo, the server computes this
	// We'll use a deterministic placeholder that's consistent
	// Must be exactly 64 hex characters (32 bytes)
	return "0e0020245000111111111111111111111111111111111111111111110e002024"
}

// ptr returns a pointer to a string.
func ptr(s string) *string {
	return &s
}

// lensPtr returns a pointer to a Lens.
func lensPtr(l steme.Lens) *steme.Lens {
	return &l
}

// printDemo1Commands prints curl commands for Demo 1.
func printDemo1Commands(hashes Demo1Hashes) {
	fmt.Println("--- Demo 1: Contradictions Visible ---")
	fmt.Println()
	fmt.Println("# Skeptic: See all competing claims")
	fmt.Println(`curl -s "http://localhost:18180/v1/skeptic?subject=semaglutide:gastroparesis_risk&predicate=risk_level" | jq`)
	fmt.Println()
	fmt.Println("# Layered: See per-tier consensus")
	fmt.Println(`curl -s "http://localhost:18180/v1/layered?subject=semaglutide:gastroparesis_risk&predicate=risk_level" | jq`)
	fmt.Println()
	fmt.Println("# Expected: conflict_score > 0.5, FDA (Tier 0) wins overall, but Anecdotal (Tier 5) disagrees")
	fmt.Println()
}

// printDemo2Commands prints curl commands for Demo 2.
func printDemo2Commands(sourceHash string) {
	fmt.Println("--- Demo 2: Cascade Invalidation ---")
	fmt.Println()
	fmt.Println("# Query assertions citing the NEJM source")
	fmt.Println(`curl -s "http://localhost:18180/v1/query?subject=GLP1_Agonists" | jq`)
	fmt.Println()
	fmt.Println("# Expected: Two assertions (cardiovascular_benefit, mortality_reduction)")
	fmt.Printf("# Both cite source_hash: %s\n", sourceHash)
	fmt.Println()
	fmt.Println("# Note: Source document storage uses base64 JSON, not raw binary.")
	fmt.Println("# The /v1/provenance endpoint retrieves stored sources.")
	fmt.Println()
}

// printDemo3Commands prints curl commands for Demo 3.
func printDemo3Commands(agentID string) {
	now := time.Now().Unix()
	from := now - 3600 // 1 hour ago

	fmt.Println("--- Demo 3: Full Audit Trail ---")
	fmt.Println()
	fmt.Println("# List recent query audits")
	fmt.Println(`curl -s "http://localhost:18180/v1/audit/queries?limit=10" | jq`)
	fmt.Println()
	fmt.Println("# Trace a specific agent's decisions")
	fmt.Printf("curl -s \"http://localhost:18180/v1/trace?agent_id=%s&from=%d&limit=50\" | jq\n", agentID, from)
	fmt.Println()
	fmt.Println("# Filter trace by subject pattern")
	fmt.Printf("curl -s \"http://localhost:18180/v1/trace?agent_id=%s&from=%d&subject=semaglutide*\" | jq\n", agentID, from)
	fmt.Println()
}

// printDemo4Commands prints curl commands for Demo 4.
func printDemo4Commands() {
	now := time.Now().Unix()
	sixMonthsAgo := now - (180 * 24 * 60 * 60)

	fmt.Println("--- Demo 4: Time Decay ---")
	fmt.Println()
	fmt.Println("# Current state with Recency lens")
	fmt.Println(`curl -s "http://localhost:18180/v1/query?subject=semaglutide&predicate=market_status&lens=Recency" | jq`)
	fmt.Println()
	fmt.Println("# Historical state (point-in-time query)")
	fmt.Printf("curl -s \"http://localhost:18180/v1/query?subject=semaglutide&predicate=market_status&lens=Recency&as_of=%d\" | jq\n", sixMonthsAgo)
	fmt.Println()
	fmt.Println("# With custom decay halflife (90 days = 7776000 seconds)")
	fmt.Println(`curl -s "http://localhost:18180/v1/query?subject=semaglutide&predicate=market_status&lens=Recency&decay_halflife=7776000" | jq`)
	fmt.Println()
}

// printDemo5Commands prints curl commands for Demo 5.
func printDemo5Commands() {
	fmt.Println("--- Demo 5: Trust & Safety ---")
	fmt.Println()
	fmt.Println("# Check quarantine queue")
	fmt.Println(`curl -s "http://localhost:18180/v1/admin/quarantine?limit=10" | jq`)
	fmt.Println()
	fmt.Println("# Check tripped circuit breakers")
	fmt.Println(`curl -s "http://localhost:18180/v1/admin/circuit-breakers/tripped" | jq`)
	fmt.Println()
	fmt.Println("# To approve a quarantined assertion:")
	fmt.Println("# curl -X POST \"http://localhost:18180/v1/admin/quarantine/{hash}/approve\"")
	fmt.Println()
	fmt.Println("# To reject a quarantined assertion:")
	fmt.Println("# curl -X POST \"http://localhost:18180/v1/admin/quarantine/{hash}/reject\"")
	fmt.Println()
	fmt.Println("# To reset a tripped circuit breaker:")
	fmt.Println("# curl -X POST \"http://localhost:18180/v1/admin/circuit-breaker/reset\" \\")
	fmt.Println("#   -H \"Content-Type: application/json\" \\")
	fmt.Println("#   -d '{\"agent_id\": \"badactor123...\"}'")
	fmt.Println()
}
