//! TrustRank-Aware Authority Lens: Resolves based on agent reputation.
//!
//! This lens integrates with TrustRank to weight assertions by the reputation
//! of the signing agent. This is the production implementation of the Authority
//! lens for Phase 4 (The Hive).
//!
//! # Design Philosophy
//!
//! Follows the "Deep Module" principle:
//! - Simple interface: `resolve_async(&[Assertion])` returns winner
//! - Complex implementation: Queries TrustRankStore, weights by reputation
//! - O(1) trust lookups via TrustRankStore

use crate::traits::{compute_conflict_score, Resolution};
use async_trait::async_trait;
use stemedb_core::types::Assertion;
use stemedb_storage::trust_rank_store::TrustRankStore;
use tracing::{debug, instrument};

/// Async version of the Lens trait for operations requiring I/O.
///
/// Re-exported from vote_aware_consensus for consistency across async lenses.
pub use crate::vote_aware_consensus::AsyncLens;

/// TrustRank-Aware Authority Lens: Returns the assertion with the highest reputation-weighted confidence.
///
/// # Resolution Strategy
///
/// 1. For each candidate assertion, lookup the primary signer's TrustRank
/// 2. Calculate weighted score: `assertion.confidence * agent.trust_rank`
/// 3. Return the assertion with highest weighted score
/// 4. Tiebreaker: If scores are equal, prefer most recent timestamp
/// 5. Agents with no TrustRank default to 0.5 (neutral reputation)
///
/// # Multi-Signature Handling
///
/// Currently uses the first signature's agent_id as the primary authority.
/// Future enhancement: Aggregate multiple signers' TrustRanks.
///
/// # Confidence Calculation
///
/// Resolution confidence is the winning assertion's weighted score normalized
/// by the maximum possible score (if the agent had perfect trust rank).
///
/// # Example
///
/// ```ignore
/// use stemedb_lens::TrustAwareAuthorityLens;
/// use stemedb_storage::{HybridStore, GenericTrustRankStore};
/// use std::sync::Arc;
///
/// let store = HybridStore::open("./data").await?;
/// let trust_store = Arc::new(GenericTrustRankStore::new(store));
/// let lens = TrustAwareAuthorityLens::new(trust_store);
///
/// let resolution = lens.resolve_async(&candidates).await;
/// ```
pub struct TrustAwareAuthorityLens<T> {
    trust_store: std::sync::Arc<T>,
}

impl<T: TrustRankStore> TrustAwareAuthorityLens<T> {
    /// Create a new TrustAwareAuthorityLens with the given TrustRankStore.
    ///
    /// The TrustRankStore is wrapped in an Arc for shared ownership, allowing
    /// the lens to be used in multiple contexts.
    pub fn new(trust_store: std::sync::Arc<T>) -> Self {
        Self { trust_store }
    }

    /// Extract the primary agent ID from an assertion.
    ///
    /// Uses the first signature's agent_id. Returns None if no signatures exist.
    fn get_primary_agent(assertion: &Assertion) -> Option<[u8; 32]> {
        assertion.signatures.first().map(|sig| sig.agent_id)
    }
}

/// Internal struct to track assertion ranking data.
#[derive(Debug)]
struct RankedAssertion<'a> {
    assertion: &'a Assertion,
    trust_score: f32,
    weighted_score: f32,
}

#[async_trait]
impl<T: TrustRankStore + 'static> AsyncLens for TrustAwareAuthorityLens<T> {
    #[instrument(skip(self, candidates), fields(candidates_count = candidates.len()))]
    async fn resolve_async(&self, candidates: &[Assertion]) -> Resolution {
        if candidates.is_empty() {
            return Resolution::empty();
        }

        // Even for single candidate, we need to calculate weighted score
        if candidates.len() == 1 {
            let assertion = &candidates[0];
            let agent_id = match Self::get_primary_agent(assertion) {
                Some(id) => id,
                None => {
                    // No signature, treat as untrusted
                    return Resolution::with_winner(assertion.clone(), 1, 0.0, 0.0);
                }
            };

            let trust_score = match self.trust_store.get_trust_rank(&agent_id).await {
                Ok(trust_rank) => trust_rank.score,
                Err(_) => 0.5, // Default trust score
            };

            let weighted_score = assertion.confidence * trust_score;
            return Resolution::with_winner(assertion.clone(), 1, weighted_score, 0.0);
        }

        // Collect trust-weighted scores for all candidates
        let mut ranked: Vec<RankedAssertion> = Vec::with_capacity(candidates.len());

        for assertion in candidates {
            // Extract primary agent
            let agent_id = match Self::get_primary_agent(assertion) {
                Some(id) => id,
                None => {
                    debug!(
                        subject = %assertion.subject,
                        "Assertion has no signatures, treating as untrusted"
                    );
                    ranked.push(RankedAssertion {
                        assertion,
                        trust_score: 0.0,
                        weighted_score: 0.0,
                    });
                    continue;
                }
            };

            // Lookup agent's TrustRank
            let trust_score = match self.trust_store.get_trust_rank(&agent_id).await {
                Ok(trust_rank) => trust_rank.score,
                Err(e) => {
                    debug!(
                        agent_id = %hex::encode(agent_id),
                        error = %e,
                        "Failed to get TrustRank, using default"
                    );
                    0.5 // Default trust score for new/unknown agents
                }
            };

            // Calculate weighted score: assertion confidence * agent trust
            let weighted_score = assertion.confidence * trust_score;

            debug!(
                subject = %assertion.subject,
                agent_id = %hex::encode(agent_id),
                confidence = assertion.confidence,
                trust_score,
                weighted_score,
                "Calculated weighted score"
            );

            ranked.push(RankedAssertion { assertion, trust_score, weighted_score });
        }

        // Sort by weighted score (descending), then by timestamp (descending) for ties
        ranked.sort_by(|a, b| {
            b.weighted_score
                .partial_cmp(&a.weighted_score)
                .unwrap_or(std::cmp::Ordering::Equal)
                .then_with(|| b.assertion.timestamp.cmp(&a.assertion.timestamp))
        });

        // Select the winner (highest ranked)
        if let Some(winner_ranked) = ranked.first() {
            // Resolution confidence is the weighted score
            // This represents how much we trust this assertion given both
            // the assertion's own confidence and the agent's reputation
            let confidence = winner_ranked.weighted_score;

            let conflict = compute_conflict_score(candidates);

            debug!(
                winner_subject = %winner_ranked.assertion.subject,
                trust_score = winner_ranked.trust_score,
                assertion_confidence = winner_ranked.assertion.confidence,
                weighted_score = winner_ranked.weighted_score,
                conflict,
                "Resolved via trust-aware authority"
            );

            Resolution::with_winner(
                winner_ranked.assertion.clone(),
                candidates.len(),
                confidence,
                conflict,
            )
        } else {
            // Should never happen since we checked for empty candidates above
            Resolution::empty()
        }
    }

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

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::Arc;
    use stemedb_core::testing::AssertionBuilder;
    use stemedb_storage::{GenericTrustRankStore, HybridStore, TrustRank, TrustRankStore};

    fn create_assertion(
        subject: &str,
        confidence: f32,
        agent_id: [u8; 32],
        timestamp: u64,
    ) -> Assertion {
        AssertionBuilder::new()
            .subject(subject)
            .confidence(confidence)
            .agent_id(agent_id)
            .timestamp(timestamp)
            .build()
    }

    #[tokio::test]
    async fn test_empty_candidates() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(trust_store);

        let resolution = lens.resolve_async(&[]).await;

        assert!(resolution.winner.is_none());
        assert_eq!(resolution.candidates_count, 0);
    }

    #[tokio::test]
    async fn test_single_candidate() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(trust_store);

        let assertion = create_assertion("Tesla", 0.8, [1u8; 32], 1000);
        let resolution = lens.resolve_async(std::slice::from_ref(&assertion)).await;

        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().unwrap().subject, "Tesla");
        // Single candidate with default trust (0.5): 0.8 * 0.5 = 0.4
        assert!((resolution.resolution_confidence - 0.4).abs() < 0.01);
    }

    #[tokio::test]
    async fn test_selects_highest_weighted_score() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(Arc::clone(&trust_store));

        // Set up agents with different trust scores
        let agent_low = [1u8; 32];
        let agent_high = [2u8; 32];

        let mut trust_low = TrustRank::new(agent_low, 1000);
        trust_low.score = 0.3; // Low trust
        trust_store.put_trust_rank(&trust_low).await.expect("put");

        let mut trust_high = TrustRank::new(agent_high, 1000);
        trust_high.score = 0.9; // High trust
        trust_store.put_trust_rank(&trust_high).await.expect("put");

        // Create assertions with same confidence but different agents
        let a1 = create_assertion("LowTrust", 0.8, agent_low, 1000);
        let a2 = create_assertion("HighTrust", 0.8, agent_high, 1100);

        // a1: 0.8 * 0.3 = 0.24
        // a2: 0.8 * 0.9 = 0.72 (winner)

        let resolution = lens.resolve_async(&[a1, a2.clone()]).await;

        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().unwrap().subject, "HighTrust");

        // Confidence should be the weighted score
        assert!((resolution.resolution_confidence - 0.72).abs() < 0.01);
    }

    #[tokio::test]
    async fn test_high_confidence_low_trust_vs_low_confidence_high_trust() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(Arc::clone(&trust_store));

        let agent1 = [1u8; 32];
        let agent2 = [2u8; 32];

        let mut trust1 = TrustRank::new(agent1, 1000);
        trust1.score = 0.4; // Low trust
        trust_store.put_trust_rank(&trust1).await.expect("put");

        let mut trust2 = TrustRank::new(agent2, 1000);
        trust2.score = 0.9; // High trust
        trust_store.put_trust_rank(&trust2).await.expect("put");

        // High confidence but low trust
        let a1 = create_assertion("HighConf", 0.95, agent1, 1000);
        // Low confidence but high trust
        let a2 = create_assertion("LowConf", 0.5, agent2, 1100);

        // a1: 0.95 * 0.4 = 0.38
        // a2: 0.5 * 0.9 = 0.45 (winner)

        let resolution = lens.resolve_async(&[a1, a2.clone()]).await;

        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().unwrap().subject, "LowConf");
    }

    #[tokio::test]
    async fn test_default_trust_for_new_agent() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(trust_store);

        // Agent with no stored TrustRank (will default to 0.5)
        let new_agent = [99u8; 32];
        let assertion = create_assertion("NewAgent", 0.8, new_agent, 1000);

        let resolution = lens.resolve_async(std::slice::from_ref(&assertion)).await;

        assert!(resolution.winner.is_some());
        // 0.8 * 0.5 (default) = 0.4
        assert!((resolution.resolution_confidence - 0.4).abs() < 0.01);
    }

    #[tokio::test]
    async fn test_no_signatures_treated_as_untrusted() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(Arc::clone(&trust_store));

        let agent_trusted = [1u8; 32];
        let mut trust = TrustRank::new(agent_trusted, 1000);
        trust.score = 0.8;
        trust_store.put_trust_rank(&trust).await.expect("put");

        let trusted = create_assertion("Trusted", 0.7, agent_trusted, 1000);

        // Create assertion with no signatures
        let mut untrusted = create_assertion("Untrusted", 0.9, [0u8; 32], 1100);
        untrusted.signatures.clear();

        let resolution = lens.resolve_async(&[trusted.clone(), untrusted]).await;

        // Should pick the trusted one even though untrusted has higher confidence
        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().unwrap().subject, "Trusted");
    }

    #[tokio::test]
    async fn test_tie_breaking_by_timestamp() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(Arc::clone(&trust_store));

        let agent = [1u8; 32];
        let mut trust = TrustRank::new(agent, 1000);
        trust.score = 0.8;
        trust_store.put_trust_rank(&trust).await.expect("put");

        // Same agent, same confidence, different timestamps
        let older = create_assertion("Older", 0.7, agent, 1000);
        let newer = create_assertion("Newer", 0.7, agent, 2000);

        // Both: 0.7 * 0.8 = 0.56
        let resolution = lens.resolve_async(&[older, newer.clone()]).await;

        // With equal weighted scores, should pick the newer timestamp
        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().unwrap().subject, "Newer");
    }

    #[tokio::test]
    async fn test_lens_name() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(trust_store);

        assert_eq!(lens.name(), "TrustAwareAuthority");
    }

    #[tokio::test]
    async fn test_multiple_candidates_different_trust_levels() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(Arc::clone(&trust_store));

        // Create agents with varying trust levels
        let agent_novice = [1u8; 32];
        let agent_expert = [2u8; 32];
        let agent_master = [3u8; 32];

        let mut trust_novice = TrustRank::new(agent_novice, 1000);
        trust_novice.score = 0.2;
        trust_store.put_trust_rank(&trust_novice).await.expect("put");

        let mut trust_expert = TrustRank::new(agent_expert, 1000);
        trust_expert.score = 0.7;
        trust_store.put_trust_rank(&trust_expert).await.expect("put");

        let mut trust_master = TrustRank::new(agent_master, 1000);
        trust_master.score = 0.95;
        trust_store.put_trust_rank(&trust_master).await.expect("put");

        let a1 = create_assertion("Novice", 0.9, agent_novice, 1000);
        let a2 = create_assertion("Expert", 0.8, agent_expert, 1100);
        let a3 = create_assertion("Master", 0.75, agent_master, 1200);

        // a1: 0.9 * 0.2 = 0.18
        // a2: 0.8 * 0.7 = 0.56
        // a3: 0.75 * 0.95 = 0.7125 (winner)

        let resolution = lens.resolve_async(&[a1, a2, a3.clone()]).await;

        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().unwrap().subject, "Master");
        assert!((resolution.resolution_confidence - 0.7125).abs() < 0.01);
    }

    #[tokio::test]
    async fn test_zero_trust_agent() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(Arc::clone(&trust_store));

        let agent_banned = [1u8; 32];
        let agent_good = [2u8; 32];

        // Banned agent with 0 trust (perhaps due to repeated inaccuracies)
        let mut trust_banned = TrustRank::new(agent_banned, 1000);
        trust_banned.score = 0.0;
        trust_store.put_trust_rank(&trust_banned).await.expect("put");

        let mut trust_good = TrustRank::new(agent_good, 1000);
        trust_good.score = 0.6;
        trust_store.put_trust_rank(&trust_good).await.expect("put");

        let banned_assertion = create_assertion("Banned", 1.0, agent_banned, 1000);
        let good_assertion = create_assertion("Good", 0.5, agent_good, 1100);

        // banned: 1.0 * 0.0 = 0.0
        // good: 0.5 * 0.6 = 0.3 (winner)

        let resolution = lens.resolve_async(&[banned_assertion, good_assertion.clone()]).await;

        assert!(resolution.winner.is_some());
        assert_eq!(resolution.winner.as_ref().unwrap().subject, "Good");
    }

    #[tokio::test]
    async fn test_perfect_trust_agent() {
        let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
        let trust_store = Arc::new(GenericTrustRankStore::new(store));
        let lens = TrustAwareAuthorityLens::new(Arc::clone(&trust_store));

        let agent_perfect = [1u8; 32];

        let mut trust_perfect = TrustRank::new(agent_perfect, 1000);
        trust_perfect.score = 1.0;
        trust_store.put_trust_rank(&trust_perfect).await.expect("put");

        let assertion = create_assertion("Perfect", 0.85, agent_perfect, 1000);

        let resolution = lens.resolve_async(std::slice::from_ref(&assertion)).await;

        assert!(resolution.winner.is_some());
        // 0.85 * 1.0 = 0.85
        assert!((resolution.resolution_confidence - 0.85).abs() < 0.01);
    }
}
