package steme

// QueryParams defines parameters for querying assertions.
//
// All fields are optional. Use QueryBuilder for fluent construction.
type QueryParams struct {
	// Filter by subject entity
	Subject *string `json:"subject,omitempty"`

	// Filter by predicate/relation
	Predicate *string `json:"predicate,omitempty"`

	// Filter by lifecycle stage
	Lifecycle *LifecycleStage `json:"lifecycle,omitempty"`

	// Filter by epoch (hex-encoded)
	Epoch *string `json:"epoch,omitempty"`

	// Apply a lens for conflict resolution
	Lens *Lens `json:"lens,omitempty"`

	// Maximum number of results to return (defaults to 100)
	Limit int `json:"limit,omitempty"`

	// Filter by visual similarity (hex-encoded pHash, 16 chars).
	// Returns assertions whose visual_hash has hamming distance <= VisualThreshold.
	VisualNear *string `json:"visual_near,omitempty"`

	// Maximum hamming distance for visual matching (0-64, default: 8).
	// Lower values require closer visual similarity.
	VisualThreshold *uint32 `json:"visual_threshold,omitempty"`
}

// QueryBuilder provides a fluent API for building query parameters.
type QueryBuilder struct {
	params QueryParams
}

// NewQuery creates a new query builder.
//
// Example:
//
//	params := steme.NewQuery().
//	    WithSubject("Tesla_Inc").
//	    WithPredicate("has_revenue").
//	    WithLens(steme.LensConsensus).
//	    WithLimit(10).
//	    Build()
func NewQuery() *QueryBuilder {
	return &QueryBuilder{
		params: QueryParams{
			Limit: 100, // Default limit
		},
	}
}

// WithSubject filters by subject entity.
func (b *QueryBuilder) WithSubject(subject string) *QueryBuilder {
	b.params.Subject = &subject
	return b
}

// WithPredicate filters by predicate/relation.
func (b *QueryBuilder) WithPredicate(predicate string) *QueryBuilder {
	b.params.Predicate = &predicate
	return b
}

// WithLifecycle filters by lifecycle stage.
func (b *QueryBuilder) WithLifecycle(lifecycle LifecycleStage) *QueryBuilder {
	b.params.Lifecycle = &lifecycle
	return b
}

// WithEpoch filters by epoch (hex-encoded, 32 bytes).
func (b *QueryBuilder) WithEpoch(epochHex string) *QueryBuilder {
	b.params.Epoch = &epochHex
	return b
}

// WithLens applies a conflict resolution lens.
func (b *QueryBuilder) WithLens(lens Lens) *QueryBuilder {
	b.params.Lens = &lens
	return b
}

// WithLimit sets the maximum number of results.
func (b *QueryBuilder) WithLimit(limit int) *QueryBuilder {
	b.params.Limit = limit
	return b
}

// WithVisualNear filters by visual similarity to a reference pHash.
//
// This enables finding assertions with visually similar screenshots or images.
// The hash should be a hex-encoded 8-byte perceptual hash (16 characters).
//
// The threshold is the maximum hamming distance (0-64, default: 8):
//   - 0: Exact match only
//   - 8: ~12.5% bit difference, catches resizing/compression
//   - 16: ~25% bit difference, more lenient
//
// Assertions without a visual_hash are excluded from results.
//
// Example:
//
//	params := steme.NewQuery().
//	    WithSubject("Tesla_10K").
//	    WithVisualNear("a3f2b1c4d5e6f708", 5).
//	    Build()
func (b *QueryBuilder) WithVisualNear(hash string, threshold uint32) *QueryBuilder {
	b.params.VisualNear = &hash
	b.params.VisualThreshold = &threshold
	return b
}

// Build returns the constructed QueryParams.
func (b *QueryBuilder) Build() QueryParams {
	return b.params
}

// QueryResult represents the response from a query operation.
type QueryResult struct {
	// Matching assertions
	Assertions []AssertionResponse `json:"assertions"`

	// Total number of results returned
	TotalCount int `json:"total_count"`

	// Whether there are more results beyond the limit
	HasMore bool `json:"has_more"`
}

// AssertionResponse represents a single assertion in query results.
type AssertionResponse struct {
	// Content-addressed hash of this assertion (hex-encoded)
	Hash string `json:"hash"`

	// The subject entity
	Subject string `json:"subject"`

	// The predicate/relation
	Predicate string `json:"predicate"`

	// The object value
	Object ObjectValue `json:"object"`

	// Confidence score (0.0 to 1.0)
	Confidence float64 `json:"confidence"`

	// Hash of parent assertion (hex-encoded, optional)
	ParentHash *string `json:"parent_hash,omitempty"`

	// Hash of source evidence (hex-encoded)
	SourceHash string `json:"source_hash"`

	// Source authority tier
	SourceClass SourceClass `json:"source_class"`

	// Perceptual hash for visual anchoring (hex-encoded, optional)
	VisualHash *string `json:"visual_hash,omitempty"`

	// Epoch ID (hex-encoded, optional)
	Epoch *string `json:"epoch,omitempty"`

	// Lifecycle stage
	Lifecycle LifecycleStage `json:"lifecycle"`

	// Agent signatures
	Signatures []SignatureEntry `json:"signatures"`

	// Creation timestamp (Unix epoch)
	Timestamp uint64 `json:"timestamp"`

	// Semantic embedding vector (optional)
	Vector []float32 `json:"vector,omitempty"`
}

// CreateResponse represents the response from a create operation.
type CreateResponse struct {
	// Content-addressed hash of the created resource (hex-encoded)
	Hash string `json:"hash"`

	// Status message
	Status string `json:"status"`
}

// SkepticQueryParams defines parameters for the skeptic endpoint.
type SkepticQueryParams struct {
	// Subject entity to analyze (required)
	Subject string `json:"subject"`

	// Predicate/relation to analyze (required)
	Predicate string `json:"predicate"`
}

// SkepticResult represents the "Trust but Verify" response.
//
// Unlike QueryResult which picks a winner, SkepticResult shows all
// competing claims with their relative weights.
type SkepticResult struct {
	// The subject that was queried
	Subject string `json:"subject"`

	// The predicate that was queried
	Predicate string `json:"predicate"`

	// Overall resolution status
	Status ResolutionStatus `json:"status"`

	// Conflict score (0.0 = unanimous, 1.0 = chaos)
	ConflictScore float64 `json:"conflict_score"`

	// All distinct claims, ranked by weight_share descending
	Claims []ClaimSummary `json:"claims"`

	// Total number of candidate assertions considered
	CandidatesCount int `json:"candidates_count"`

	// Unix timestamp when this view was computed
	ComputedAt uint64 `json:"computed_at"`

	// Which lens was used (always "Skeptic")
	LensName string `json:"lens_name"`
}

// ClaimSummary represents a single competing claim.
type ClaimSummary struct {
	// The claimed value
	Value ObjectValue `json:"value"`

	// Normalized weight (0.0 to 1.0) relative to all claims
	WeightShare float64 `json:"weight_share"`

	// Number of assertions making this exact claim
	AssertionCount uint32 `json:"assertion_count"`

	// Hash of the representative assertion (hex-encoded)
	RepresentativeHash string `json:"representative_hash"`

	// Source provenance
	Source SourceSummary `json:"source"`

	// Agents supporting this claim
	SupportingAgents []AgentSummary `json:"supporting_agents"`
}

// SourceSummary provides minimal source info for provenance.
type SourceSummary struct {
	// Hash of the source document (hex-encoded)
	SourceHash string `json:"source_hash"`

	// Visual anchor hash (hex-encoded, optional)
	VisualHash *string `json:"visual_hash,omitempty"`
}

// AgentSummary provides minimal agent info for attribution.
type AgentSummary struct {
	// Agent's public key (hex-encoded)
	AgentID string `json:"agent_id"`

	// Trust score at query time (0.0 to 1.0)
	TrustScore float64 `json:"trust_score"`
}

// LayeredQueryParams defines parameters for the layered consensus endpoint.
type LayeredQueryParams struct {
	// Subject entity to analyze (required)
	Subject string `json:"subject"`

	// Predicate/relation to analyze (required)
	Predicate string `json:"predicate"`
}

// LayeredResult represents the response from a layered consensus query.
//
// Provides per-tier resolution results plus an overall winner.
// Use this to see "What does Tier 0 (FDA) say? What does Tier 5 (Reddit) say?"
type LayeredResult struct {
	// The subject that was queried
	Subject string `json:"subject"`

	// The predicate that was queried
	Predicate string `json:"predicate"`

	// Per-tier consensus results, ordered by tier (0 = highest authority first)
	// Only tiers with at least one candidate are included.
	Tiers []TierResolution `json:"tiers"`

	// Overall winner: winner from the highest-authority tier that has candidates
	OverallWinner *AssertionResponse `json:"overall_winner,omitempty"`

	// Cross-tier disagreement score (0.0 = tiers agree, 1.0 = tiers disagree)
	OverallConflictScore float64 `json:"overall_conflict_score"`

	// Total candidates considered across all tiers
	TotalCandidates int `json:"total_candidates"`

	// Unix timestamp when this view was computed
	ComputedAt uint64 `json:"computed_at"`

	// Which lens was used (always "LayeredConsensus")
	LensName string `json:"lens_name"`
}

// TierResolution represents the consensus within a single source class tier.
type TierResolution struct {
	// The tier number (0-5). Lower = higher authority.
	Tier int `json:"tier"`

	// The source class for this tier
	SourceClass SourceClass `json:"source_class"`

	// The winning assertion from within-tier consensus, if any candidates
	Winner *AssertionResponse `json:"winner,omitempty"`

	// Number of candidates in this tier
	CandidatesCount int `json:"candidates_count"`

	// Within-tier conflict score (0.0 = unanimous, 1.0 = max conflict)
	ConflictScore float64 `json:"conflict_score"`

	// Within-tier resolution confidence (0.0 to 1.0)
	ResolutionConfidence float64 `json:"resolution_confidence"`
}

// TraceParams defines parameters for tracing agent queries.
//
// Used to debug "Why did the agent think that?" for incident investigation.
type TraceParams struct {
	// Agent public key to trace (hex-encoded, 32 bytes) - required
	AgentID string `json:"agent_id"`

	// Start of time range (Unix timestamp) - required
	From string `json:"from"`

	// End of time range (Unix timestamp, defaults to now)
	To string `json:"to,omitempty"`

	// Filter by subject pattern (e.g., "Tesla*", "auth/*")
	Subject string `json:"subject,omitempty"`

	// Maximum number of results (default: 100)
	Limit int `json:"limit,omitempty"`
}

// TraceResult represents the response from a trace operation.
type TraceResult struct {
	// Matching query audit records
	Audits []QueryAuditRecord `json:"audits"`

	// Total number of results returned
	TotalCount int `json:"total_count"`

	// Agent ID that was traced (hex-encoded)
	AgentID string `json:"agent_id"`

	// Time range start (Unix timestamp)
	FromTimestamp uint64 `json:"from_timestamp"`

	// Time range end (Unix timestamp)
	ToTimestamp uint64 `json:"to_timestamp"`
}

// QueryAuditRecord represents a single query audit entry.
type QueryAuditRecord struct {
	// Unique identifier for this query (hex-encoded, 32 bytes)
	QueryID string `json:"query_id"`

	// Agent public key who made the query (hex-encoded, optional)
	AgentID *string `json:"agent_id,omitempty"`

	// Unix timestamp when the query was executed
	Timestamp uint64 `json:"timestamp"`

	// Query parameters that were used
	Params QueryParamsAudit `json:"params"`

	// Hash of the winning assertion (hex-encoded, optional)
	ResultHash *string `json:"result_hash,omitempty"`

	// Confidence score of the result
	ResultConfidence float32 `json:"result_confidence"`

	// Assertions that contributed to the result
	ContributingAssertions []ContributingAssertion `json:"contributing_assertions"`
}

// QueryParamsAudit represents the parameters used in a query.
type QueryParamsAudit struct {
	// Subject filter (optional)
	Subject *string `json:"subject,omitempty"`

	// Predicate filter (optional)
	Predicate *string `json:"predicate,omitempty"`

	// Lifecycle filter (optional)
	Lifecycle *LifecycleStage `json:"lifecycle,omitempty"`

	// Epoch filter (hex-encoded, optional)
	Epoch *string `json:"epoch,omitempty"`

	// Lens used (optional)
	Lens *Lens `json:"lens,omitempty"`
}

// ContributingAssertion represents an assertion that contributed to a query result.
type ContributingAssertion struct {
	// Hash of the assertion (hex-encoded)
	AssertionHash string `json:"assertion_hash"`

	// Weight in the resolution (1.0 for winner)
	Weight float32 `json:"weight"`

	// Hash of the source evidence (hex-encoded)
	SourceHash string `json:"source_hash"`

	// Lifecycle stage of the assertion
	Lifecycle LifecycleStage `json:"lifecycle"`
}

// SupersessionType defines how an assertion is being superseded.
type SupersessionType string

const (
	// SupersessionInvalidate means the old assertion was factually incorrect.
	SupersessionInvalidate SupersessionType = "Invalidate"

	// SupersessionTemporal means the old assertion was correct but now outdated.
	SupersessionTemporal SupersessionType = "Temporal"

	// SupersessionRefinement means the old assertion was a simplification.
	SupersessionRefinement SupersessionType = "Refinement"

	// SupersessionRequiresReview means the old assertion needs human review.
	SupersessionRequiresReview SupersessionType = "RequiresReview"

	// SupersessionAdditive means the new assertion adds context without invalidating.
	SupersessionAdditive SupersessionType = "Additive"
)

// SupersedeParams defines parameters for creating a supersession.
type SupersedeParams struct {
	// Hash of the assertion being superseded (hex-encoded, 32 bytes)
	TargetHash string `json:"target_hash"`

	// How the target is being superseded
	SupersessionType SupersessionType `json:"supersession_type"`

	// Human-readable explanation (for audit trail)
	Reason string `json:"reason"`

	// Hash of the replacement assertion (hex-encoded, optional)
	// None for RequiresReview or pure invalidation.
	NewHash string `json:"new_hash,omitempty"`

	// Public key of the agent creating the supersession (hex-encoded, 32 bytes)
	AgentID string `json:"agent_id"`

	// Signature over the supersession content (hex-encoded, 64 bytes)
	Signature string `json:"signature"`
}

// SupersedeResult represents the response from a supersede operation.
type SupersedeResult struct {
	// Status message
	Status string `json:"status"`

	// Hash of the target assertion that was superseded (hex-encoded)
	TargetHash string `json:"target_hash"`

	// Type of supersession applied
	SupersessionType SupersessionType `json:"supersession_type"`

	// Unix timestamp when the supersession was recorded
	Timestamp uint64 `json:"timestamp"`
}
