//! Confidence Lens: Highest assertion confidence field wins.
//!
//! This lens selects assertions based on their self-declared `confidence` field.
//! It does NOT consider agent reputation or TrustRank - for reputation-aware
//! resolution, use `TrustAwareAuthorityLens`.
//!
//! # When to Use
//!
//! Use `ConfidenceLens` when:
//! - Assertions have meaningful confidence scores from their sources
//! - You want to prefer high-certainty claims over low-certainty ones
//! - Agent reputation is not a factor (or is handled elsewhere)
//!
//! Use `TrustAwareAuthorityLens` when:
//! - You want to weight by agent reputation (TrustRank)
//! - Agent history matters more than self-declared confidence

use crate::traits::{compute_conflict_score, Lens, Resolution};
use stemedb_core::types::Assertion;
use tracing::instrument;

/// Confidence Lens: Returns the assertion with the highest confidence field.
///
/// # Resolution Strategy
///
/// 1. Find assertion with maximum `confidence` field value
/// 2. If tie: prefer most recent (timestamp tiebreaker)
///
/// # Confidence Calculation
///
/// Resolution confidence equals the winning assertion's confidence field.
///
/// # Example
///
/// ```ignore
/// use stemedb_lens::{ConfidenceLens, Lens};
///
/// let lens = ConfidenceLens;
/// let resolution = lens.resolve(&candidates);
/// // Returns assertion with highest confidence field
/// ```
#[derive(Debug, Clone, Copy, Default)]
pub struct ConfidenceLens;

impl Lens for ConfidenceLens {
    #[instrument(skip(self, candidates), fields(candidates_count = candidates.len(), lens = "Confidence"))]
    fn resolve(&self, candidates: &[Assertion]) -> Resolution {
        if candidates.is_empty() {
            return Resolution::empty();
        }

        if candidates.len() == 1 {
            return Resolution::with_winner(candidates[0].clone(), 1, 1.0, 0.0);
        }

        // Find the assertion with the highest confidence
        let winner = candidates
            .iter()
            .max_by(|a, b| {
                // Primary: highest confidence
                // Tiebreaker: most recent timestamp
                a.confidence
                    .partial_cmp(&b.confidence)
                    .unwrap_or(std::cmp::Ordering::Equal)
                    .then_with(|| a.timestamp.cmp(&b.timestamp))
            })
            .cloned();

        match winner {
            Some(w) => {
                // Resolution confidence is the winning assertion's confidence
                let confidence = w.confidence;
                let conflict = compute_conflict_score(candidates);
                Resolution::with_winner(w, candidates.len(), confidence, conflict)
            }
            None => Resolution::empty(),
        }
    }

    fn name(&self) -> &'static str {
        "Confidence"
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use stemedb_core::testing::AssertionBuilder;

    fn create_assertion(subject: &str, confidence: f32, timestamp: u64) -> Assertion {
        AssertionBuilder::new().subject(subject).confidence(confidence).timestamp(timestamp).build()
    }

    #[test]
    fn test_empty_candidates() {
        let lens = ConfidenceLens;
        let resolution = lens.resolve(&[]);

        assert!(resolution.winner.is_none());
    }

    #[test]
    fn test_selects_highest_confidence() {
        let lens = ConfidenceLens;

        let low = create_assertion("Low", 0.3, 1000);
        let high = create_assertion("High", 0.95, 900);
        let medium = create_assertion("Medium", 0.6, 1100);

        let resolution = lens.resolve(&[low, high.clone(), medium]);

        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().map(|a| &a.subject), Some(&"High".to_string()));
    }

    #[test]
    fn test_tiebreaker_uses_timestamp() {
        let lens = ConfidenceLens;

        let older = create_assertion("Older", 0.9, 1000);
        let newer = create_assertion("Newer", 0.9, 2000);

        let resolution = lens.resolve(&[older, newer.clone()]);

        // Same confidence, should pick newer
        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().map(|a| &a.subject), Some(&"Newer".to_string()));
    }

    #[test]
    fn test_resolution_confidence_matches_winner() {
        let lens = ConfidenceLens;
        let high_conf = create_assertion("High", 0.85, 1000);
        let low_conf = create_assertion("Low", 0.3, 900);

        let resolution = lens.resolve(&[high_conf, low_conf]);

        // Resolution confidence should match the winning assertion's confidence
        assert!((resolution.resolution_confidence - 0.85).abs() < f32::EPSILON);
    }

    #[test]
    fn test_lens_name() {
        let lens = ConfidenceLens;
        assert_eq!(lens.name(), "Confidence");
    }

    #[test]
    fn test_nan_confidence_falls_back_to_timestamp() {
        let lens = ConfidenceLens;

        // NaN compared to any value returns Ordering::Equal via unwrap_or
        // So tiebreaker (timestamp) decides the winner
        let normal_older = create_assertion("NormalOlder", 0.5, 1000);
        let mut nan_newer = create_assertion("NaNNewer", 0.0, 2000);
        nan_newer.confidence = f32::NAN;

        let resolution = lens.resolve(&[normal_older.clone(), nan_newer]);

        // NaN == 0.5 (Equal due to unwrap_or), so newer timestamp wins
        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().map(|a| &a.subject), Some(&"NaNNewer".to_string()));
    }

    #[test]
    fn test_nan_confidence_loses_to_newer_normal() {
        let lens = ConfidenceLens;

        // When normal assertion has newer timestamp, it wins (NaN treated as equal)
        let mut nan_older = create_assertion("NaNOlder", 0.0, 1000);
        nan_older.confidence = f32::NAN;
        let normal_newer = create_assertion("NormalNewer", 0.5, 2000);

        let resolution = lens.resolve(&[nan_older, normal_newer.clone()]);

        // NaN == 0.5 (Equal), tiebreaker picks newer timestamp
        assert!(resolution.winner.is_some());
        assert_eq!(
            resolution.winner.as_ref().map(|a| &a.subject),
            Some(&"NormalNewer".to_string())
        );
    }

    #[test]
    fn test_all_nan_confidence_uses_timestamp() {
        let lens = ConfidenceLens;

        let mut older_nan = create_assertion("OlderNaN", 0.0, 1000);
        older_nan.confidence = f32::NAN;
        let mut newer_nan = create_assertion("NewerNaN", 0.0, 2000);
        newer_nan.confidence = f32::NAN;

        let resolution = lens.resolve(&[older_nan, newer_nan.clone()]);

        // When all are NaN (equal), tiebreaker should pick newer timestamp
        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().map(|a| &a.subject), Some(&"NewerNaN".to_string()));
    }
}
