//! Observation types for LLM evaluation tracking.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// A single LLM extraction observation with full context.
///
/// Each observation captures everything needed to reproduce and analyze
/// an LLM extraction attempt: the prompt, input content, raw response,
/// parsed claims, and performance metrics.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Observation {
    /// Unique identifier for this observation.
    pub id: Uuid,

    /// When this observation was recorded.
    pub timestamp: DateTime<Utc>,

    /// Semantic version of the prompt (e.g., "v1.2.0").
    pub prompt_version: String,

    /// BLAKE3 hash of the system prompt (for cache invalidation tracking).
    pub prompt_hash: String,

    /// Model identifier (e.g., "gemini-3-flash-preview").
    pub model: String,

    /// BLAKE3 hash of the input content.
    pub input_hash: String,

    /// Path to the file being analyzed.
    pub file_path: String,

    /// Detected language of the file.
    pub language: String,

    /// Length of the input content in bytes.
    pub content_length: usize,

    /// Raw LLM response text (before parsing).
    pub raw_response: String,

    /// Claims parsed from the LLM response.
    pub parsed_claims: Vec<ParsedClaim>,

    /// Final claims after ontology validation and fuzzy matching.
    pub final_claims: Vec<FinalClaim>,

    /// Number of input tokens consumed.
    pub input_tokens: usize,

    /// Number of output tokens generated.
    pub output_tokens: usize,

    /// Whether JSON parsing succeeded.
    pub parse_success: bool,

    /// Error message if parsing failed.
    pub parse_error: Option<String>,

    /// Whether this response came from cache.
    pub cache_hit: bool,

    /// Total latency in milliseconds.
    pub latency_ms: u64,
}

/// A claim as parsed directly from LLM JSON output.
///
/// These are the raw claims before ontology validation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ParsedClaim {
    /// Subject path from LLM (may not match ontology).
    pub subject: String,

    /// Predicate from LLM.
    pub predicate: String,

    /// Value from LLM (preserves JSON type).
    pub value: serde_json::Value,

    /// Confidence score from LLM (0.0-1.0).
    pub confidence: f32,

    /// Line number in source file.
    pub line: usize,
}

/// A claim after ontology validation and transformation.
///
/// These are the claims that will be ingested into Episteme.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FinalClaim {
    /// Full concept path (code://language/path/to/concept).
    pub concept_path: String,

    /// Predicate (validated against ontology).
    pub predicate: String,

    /// Value (converted to appropriate type).
    pub value: serde_json::Value,

    /// Final confidence score.
    pub confidence: f32,

    /// Whether this matched an exact ontology concept.
    pub matched_ontology: bool,

    /// Whether this was fuzzy-matched to an ontology concept.
    pub fuzzy_matched: bool,
}
