//! TrustRankStore implementation backed by a generic KVStore.
//!
//! This module provides the concrete implementation of TrustRankStore operations,
//! including CRUD operations, decay mechanics, and learning loop integration.

use crate::error::Result;
use crate::key_codec;
use crate::traits::KVStore;
use async_trait::async_trait;
use tracing::{debug, instrument};

use super::model::{TrustRank, DEFAULT_HALF_LIFE_SECONDS};
use super::TrustRankStore;

/// TrustRankStore implementation backed by a generic KVStore.
///
/// This implementation stores TrustRank data at `\x00TRUST:{agent_id_hex}` and provides
/// all operations for reputation management.
pub struct GenericTrustRankStore<S> {
    store: S,
}

impl<S: KVStore> GenericTrustRankStore<S> {
    /// Create a new TrustRankStore backed by the given KVStore.
    pub fn new(store: S) -> Self {
        Self { store }
    }

    /// Serialize a TrustRank using the canonical serde helpers.
    pub(crate) fn serialize_trust_rank(trust_rank: &TrustRank) -> Result<Vec<u8>> {
        crate::serde_helpers::serialize(trust_rank)
    }

    /// Deserialize a TrustRank using the canonical serde helpers.
    pub(crate) fn deserialize_trust_rank(data: &[u8]) -> Result<TrustRank> {
        crate::serde_helpers::deserialize(data)
    }
}

#[async_trait]
impl<S: KVStore + 'static> TrustRankStore for GenericTrustRankStore<S> {
    #[instrument(skip(self), fields(agent_id = %hex::encode(agent_id)))]
    async fn get_trust_rank(&self, agent_id: &[u8; 32]) -> Result<TrustRank> {
        let key = key_codec::trust_rank_key(&hex::encode(agent_id));
        match self.store.get(&key).await? {
            Some(data) => {
                let trust_rank = Self::deserialize_trust_rank(&data)?;
                debug!(score = trust_rank.score, "Retrieved TrustRank");
                Ok(trust_rank)
            }
            None => {
                // New agent, return default
                let now = std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .map(|d| d.as_secs())
                    .unwrap_or(0);
                let trust_rank = TrustRank::new(*agent_id, now);
                debug!(score = trust_rank.score, "Created default TrustRank for new agent");
                Ok(trust_rank)
            }
        }
    }

    #[instrument(skip(self), fields(agent_id = %hex::encode(agent_id), delta))]
    async fn update_trust_rank(
        &self,
        agent_id: &[u8; 32],
        delta: f32,
        timestamp: u64,
    ) -> Result<f32> {
        let mut trust_rank = self.get_trust_rank(agent_id).await?;
        let new_score = trust_rank.adjust_score(delta, timestamp);

        let serialized = Self::serialize_trust_rank(&trust_rank)?;
        let key = key_codec::trust_rank_key(&hex::encode(agent_id));
        self.store.put(&key, &serialized).await?;

        debug!(new_score, "Updated TrustRank");
        Ok(new_score)
    }

    #[instrument(skip(self), fields(current_timestamp, half_life_seconds))]
    async fn decay_trust_ranks(
        &self,
        current_timestamp: u64,
        half_life_seconds: Option<u64>,
    ) -> Result<usize> {
        let half_life = half_life_seconds.unwrap_or(DEFAULT_HALF_LIFE_SECONDS);
        let prefix = key_codec::trust_rank_scan_prefix();
        let entries = self.store.scan_prefix(&prefix).await?;

        let mut decayed_count = 0;

        for (key, data) in entries {
            let mut trust_rank = Self::deserialize_trust_rank(&data)?;
            let old_score = trust_rank.score;
            trust_rank.apply_decay(current_timestamp, half_life);

            // Only update if score actually changed
            if (trust_rank.score - old_score).abs() > f32::EPSILON {
                let serialized = Self::serialize_trust_rank(&trust_rank)?;
                self.store.put(&key, &serialized).await?;
                decayed_count += 1;

                debug!(
                    agent_id = %hex::encode(trust_rank.agent_id),
                    old_score,
                    new_score = trust_rank.score,
                    "Decayed TrustRank"
                );
            }
        }

        debug!(decayed_count, "Completed TrustRank decay");
        Ok(decayed_count)
    }

    #[instrument(skip(self), fields(agent_id = %hex::encode(agent_id), was_accurate))]
    async fn record_outcome(
        &self,
        agent_id: &[u8; 32],
        was_accurate: bool,
        timestamp: u64,
    ) -> Result<f32> {
        let mut trust_rank = self.get_trust_rank(agent_id).await?;

        // Record the outcome
        trust_rank.record_outcome(was_accurate);

        // Adjust score based on accuracy
        // Accurate: +0.05, Inaccurate: -0.1 (penalty is higher to discourage spam)
        let delta = if was_accurate { 0.05 } else { -0.1 };
        let new_score = trust_rank.adjust_score(delta, timestamp);

        let serialized = Self::serialize_trust_rank(&trust_rank)?;
        let key = key_codec::trust_rank_key(&hex::encode(agent_id));
        self.store.put(&key, &serialized).await?;

        debug!(
            new_score,
            accuracy_rate = trust_rank.accuracy_rate(),
            "Recorded outcome and updated TrustRank"
        );
        Ok(new_score)
    }

    #[instrument(skip(self, trust_rank), fields(agent_id = %hex::encode(trust_rank.agent_id)))]
    async fn put_trust_rank(&self, trust_rank: &TrustRank) -> Result<()> {
        let serialized = Self::serialize_trust_rank(trust_rank)?;
        let key = key_codec::trust_rank_key(&hex::encode(trust_rank.agent_id));
        self.store.put(&key, &serialized).await?;
        debug!(score = trust_rank.score, "Stored TrustRank");
        Ok(())
    }

    #[instrument(skip(self, gold_standard), fields(
        agent_id = %hex::encode(agent_id),
        subject = %gold_standard.subject,
        predicate = %gold_standard.predicate,
        agent_object = %agent_object
    ))]
    async fn verify_agent_against_gold_standard(
        &self,
        agent_id: &[u8; 32],
        agent_object: &str,
        gold_standard: &stemedb_core::types::GoldStandard,
        timestamp: u64,
    ) -> Result<super::model::TrustAdjustment> {
        use super::model::TrustAdjustment;

        // Check if the agent has already verified this gold standard
        let verified_key = key_codec::gs_verified_key(
            &hex::encode(agent_id),
            &gold_standard.subject,
            &gold_standard.predicate,
        );
        if self.store.get(&verified_key).await?.is_some() {
            debug!("Agent has already verified this gold standard");
            return Ok(TrustAdjustment::AlreadyVerified);
        }

        let mut trust_rank = self.get_trust_rank(agent_id).await?;

        // Check if the agent's answer matches the gold standard
        let is_correct = gold_standard.matches(agent_object);

        // Record the outcome for accuracy tracking
        trust_rank.record_outcome(is_correct);

        // Determine the adjustment
        let adjustment = if is_correct {
            // Reward: +0.05
            let reward = 0.05;
            trust_rank.adjust_score(reward, timestamp);
            TrustAdjustment::Rewarded(reward)
        } else {
            // Penalty: -0.1
            let penalty = 0.1;
            trust_rank.adjust_score(-penalty, timestamp);
            TrustAdjustment::Penalized(penalty)
        };

        // Store the updated trust rank
        let serialized = Self::serialize_trust_rank(&trust_rank)?;
        let key = key_codec::trust_rank_key(&hex::encode(agent_id));
        self.store.put(&key, &serialized).await?;

        // Mark this gold standard as verified by this agent (value is just a timestamp)
        let marker_value = timestamp.to_le_bytes();
        self.store.put(&verified_key, &marker_value).await?;

        debug!(
            adjustment = ?adjustment,
            new_score = trust_rank.score,
            accuracy_rate = trust_rank.accuracy_rate(),
            "Verified agent against gold standard"
        );

        Ok(adjustment)
    }
}
