//! Policy Enforcer - Trust-based routing and access control
//!
//! Queries QVL for trust scores and makes policy decisions.

use crate::qvl_ffi::{QvlClient, QvlError};
use std::sync::Arc;

/// Policy decision for packet handling
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PolicyDecision {
    /// Accept packet for normal processing/relay
    Accept,
    /// Deprioritize packet (low-priority queue)
    Deprioritize,
    /// Drop packet silently
    Drop,
    /// Treat as neutral (no trust data available)
    Neutral,
}

/// Trust-based policy enforcer
pub struct PolicyEnforcer {
    qvl: Arc<QvlClient>,
    
    // Policy thresholds
    drop_threshold: f64,      // Below this: drop
    untrusted_threshold: f64, // Below this: deprioritize
}

impl PolicyEnforcer {
    /// Create new policy enforcer
    pub fn new(qvl: Arc<QvlClient>) -> Self {
        Self {
            qvl,
            drop_threshold: 0.1,      // Drop if trust < 0.1
            untrusted_threshold: 0.5, // Deprioritize if trust < 0.5
        }
    }
    
    /// Create with custom thresholds
    pub fn with_thresholds(
        qvl: Arc<QvlClient>,
        drop_threshold: f64,
        untrusted_threshold: f64,
    ) -> Self {
        Self {
            qvl,
            drop_threshold,
            untrusted_threshold,
        }
    }
    
    /// Decide whether to accept a packet from a DID
    pub fn should_accept_packet(&self, sender_did: &[u8; 32]) -> PolicyDecision {
        match self.qvl.get_trust_score(sender_did) {
            Ok(score) if score < self.drop_threshold => PolicyDecision::Drop,
            Ok(score) if score < self.untrusted_threshold => PolicyDecision::Deprioritize,
            Ok(_) => PolicyDecision::Accept,
            Err(QvlError::TrustScoreFailed) | Err(QvlError::InvalidDid) => PolicyDecision::Neutral,
            Err(_) => PolicyDecision::Neutral,
        }
    }
    
    /// Check if a node should be flagged for betrayal
    pub fn check_for_betrayal(&self, node_id: u32) -> Option<f64> {
        match self.qvl.detect_betrayal(node_id) {
            Ok(anomaly) if anomaly.score > 0.7 => Some(anomaly.score),
            _ => None,
        }
    }
    
    /// Batch check multiple nodes for betrayal
    pub fn batch_check_betrayal(&self, node_ids: &[u32]) -> Vec<(u32, f64)> {
        node_ids
            .iter()
            .filter_map(|&node_id| {
                self.check_for_betrayal(node_id)
                    .map(|score| (node_id, score))
            })
            .collect()
    }

    /// Check a node for betrayal and issue slash signal if guilty
    /// Returns the signed SlashSignal bytes if a punishment was issued
    pub fn punish_if_guilty(&self, node_id: u32) -> Option<[u8; 82]> {
        match self.qvl.detect_betrayal(node_id) {
            Ok(anomaly) if anomaly.score > 0.9 => { 
                // High confidence betrayal
                if let Some(did) = self.qvl.get_did(anomaly.node) {
                     // 1. Get Evidence
                     let evidence_hash = if let Ok(evidence) = self.qvl.get_betrayal_evidence(anomaly.node) {
                         // TODO: Calculate real Blake3 hash of evidence. For now use first 32 bytes or dummy.
                         let mut hash = [0xEEu8; 32];
                         if evidence.len() >= 32 {
                             hash.copy_from_slice(&evidence[0..32]);
                         }
                         hash
                     } else {
                         [0u8; 32] 
                     };

                     // 2. Issue slash
                     if let Ok(signal) = self.qvl.issue_slash_signal(&did, anomaly.reason as u8, &evidence_hash) {
                         return Some(signal);
                     }
                }
                None
            },
            _ => None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_policy_enforcer_neutral() {
        let qvl = Arc::new(QvlClient::new().unwrap());
        let enforcer = PolicyEnforcer::new(qvl);
        
        let unknown_did = [0u8; 32];
        let decision = enforcer.should_accept_packet(&unknown_did);
        
        // Unknown DIDs should be treated as Accept (neutral trust default)
        assert_eq!(decision, PolicyDecision::Accept);
    }
    
    #[test]
    fn test_betrayal_check_clean_graph() {
        let qvl = Arc::new(QvlClient::new().unwrap());
        let enforcer = PolicyEnforcer::new(qvl);
        
        // Empty graph should have no betrayal
        let result = enforcer.check_for_betrayal(0);
        assert_eq!(result, None);
    }
    
    #[test]
    fn test_batch_check() {
        let qvl = Arc::new(QvlClient::new().unwrap());
        let enforcer = PolicyEnforcer::new(qvl);
        
        let nodes = vec![0, 1, 2, 3, 4];
        let betrayals = enforcer.batch_check_betrayal(&nodes);
        
        // Clean graph should have no betrayals
        assert_eq!(betrayals.len(), 0);
    }
}
