//! Privacy-mode filter for outbound MQTT (and Matter) state messages.
//!
//! Implements the ADR-106 primitive-isolation contract at the integration
//! boundary, gated by [`crate::cli::Args::privacy_mode`]. When the flag is
//! set, biometric channels (HR, BR, raw pose keypoints) are stripped
//! from every outbound message *and* their entities are never discovered
//! by Home Assistant — `discovery.rs::DiscoveryBuilder::enabled_entities`
//! returns the filtered set.
//!
//! Semantic primitives (someone-sleeping, possible-distress, etc) stay
//! enabled in privacy mode because they're inferred *states*, not raw
//! biometric values. The inference runs server-side and only the boolean
//! / numeric state crosses the wire. This is the key design choice that
//! makes ADR-115 §3.12 enterprise- and healthcare-deployable.

use super::discovery::EntityKind;

/// Decision for one outbound publication.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PublishDecision {
    /// Send as-is.
    Publish,
    /// Drop silently (entity is suppressed by privacy mode).
    Suppress,
}

/// Decide whether an entity may be published given a privacy-mode flag.
///
/// Discovery and state share the same filter so an HA controller can't
/// learn from the absence of state that the entity might exist with
/// different filters in place — if it's stripped, it's stripped at every
/// layer.
pub fn decide(entity: EntityKind, privacy_mode: bool) -> PublishDecision {
    if privacy_mode && entity.is_biometric() {
        PublishDecision::Suppress
    } else {
        PublishDecision::Publish
    }
}

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

    #[test]
    fn privacy_off_publishes_everything() {
        for e in [
            EntityKind::Presence,
            EntityKind::HeartRate,
            EntityKind::BreathingRate,
            EntityKind::PoseKeypoints,
            EntityKind::SomeoneSleeping,
            EntityKind::PossibleDistress,
            EntityKind::FallDetected,
        ] {
            assert_eq!(decide(e, false), PublishDecision::Publish);
        }
    }

    #[test]
    fn privacy_on_suppresses_biometrics_only() {
        // HR / BR / pose keypoints → suppressed.
        assert_eq!(decide(EntityKind::HeartRate, true), PublishDecision::Suppress);
        assert_eq!(decide(EntityKind::BreathingRate, true), PublishDecision::Suppress);
        assert_eq!(decide(EntityKind::PoseKeypoints, true), PublishDecision::Suppress);
    }

    #[test]
    fn privacy_on_keeps_non_biometric_signals() {
        for e in [
            EntityKind::Presence,
            EntityKind::PersonCount,
            EntityKind::MotionLevel,
            EntityKind::Rssi,
            EntityKind::ZoneOccupancy,
            EntityKind::FallDetected,
            EntityKind::PresenceScore,
        ] {
            assert_eq!(decide(e, true), PublishDecision::Publish, "{:?} should not be suppressed", e);
        }
    }

    #[test]
    fn privacy_on_keeps_semantic_primitives() {
        // Per ADR-115 §3.12.3 — semantic primitives are *inferred* states,
        // not raw biometrics, so they remain available in privacy mode.
        // This is the core privacy win of HA-MIND.
        for e in [
            EntityKind::SomeoneSleeping,
            EntityKind::PossibleDistress,
            EntityKind::RoomActive,
            EntityKind::ElderlyInactivityAnomaly,
            EntityKind::MeetingInProgress,
            EntityKind::BathroomOccupied,
            EntityKind::FallRiskElevated,
            EntityKind::BedExit,
            EntityKind::NoMovement,
            EntityKind::MultiRoomTransition,
        ] {
            assert_eq!(decide(e, true), PublishDecision::Publish, "{:?} should not be suppressed", e);
        }
    }
}
