#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-omni -- Universal Platform Abstraction Bridge
//! Single API for Android/iOS/HarmonyOS/Desktop/Web

use std::collections::HashMap;

#[derive(Debug)]
pub enum OmniError { Unsupported(String), PermissionDenied(String), PlatformError(String) }
impl std::fmt::Display for OmniError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self { Self::Unsupported(e) => write!(f, "Unsupported: {e}"), Self::PermissionDenied(e) => write!(f, "Permission: {e}"), Self::PlatformError(e) => write!(f, "Platform: {e}") }
    }
}
impl std::error::Error for OmniError {}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Platform { Android, Ios, HarmonyOs, Desktop, Web, Unknown }

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Capability { Camera, Microphone, Gps, Bluetooth, Nfc, Haptic, Gyroscope, Lidar, FaceId, Biometric, WebTransport, WebGpu, SharedArrayBuffer }

impl Platform {
    pub fn capabilities(&self) -> Vec<Capability> {
        match self {
            Self::Android => vec![Capability::Camera, Capability::Microphone, Capability::Gps, Capability::Bluetooth, Capability::Nfc, Capability::Haptic, Capability::Gyroscope, Capability::Biometric],
            Self::Ios => vec![Capability::Camera, Capability::Microphone, Capability::Gps, Capability::Bluetooth, Capability::Nfc, Capability::Haptic, Capability::Gyroscope, Capability::Lidar, Capability::FaceId, Capability::Biometric],
            Self::HarmonyOs => vec![Capability::Camera, Capability::Microphone, Capability::Gps, Capability::Bluetooth, Capability::Nfc, Capability::Haptic, Capability::Gyroscope],
            Self::Desktop => vec![Capability::Camera, Capability::Microphone, Capability::WebTransport, Capability::WebGpu, Capability::SharedArrayBuffer],
            Self::Web => vec![Capability::Camera, Capability::Microphone, Capability::WebTransport, Capability::WebGpu],
            Self::Unknown => vec![],
        }
    }
    pub fn has_capability(&self, cap: Capability) -> bool { self.capabilities().contains(&cap) }
    pub fn detect_from_user_agent(ua: &str) -> Self {
        let ua_lower = ua.to_lowercase();
        if ua_lower.contains("android") { Self::Android }
        else if ua_lower.contains("iphone") || ua_lower.contains("ipad") { Self::Ios }
        else if ua_lower.contains("harmonyos") || ua_lower.contains("huawei") { Self::HarmonyOs }
        else if ua_lower.contains("windows") || ua_lower.contains("macintosh") || ua_lower.contains("linux") { Self::Desktop }
        else if ua_lower.contains("mozilla") { Self::Web }
        else { Self::Unknown }
    }
}

/// Feature negotiation between client and server
pub struct OmniBridge {
    platform: Platform,
    granted_permissions: Vec<Capability>,
    features: HashMap<String, bool>,
}

impl OmniBridge {
    pub fn new(platform: Platform) -> Self {
        Self { platform, granted_permissions: Vec::new(), features: HashMap::new() }
    }

    pub fn from_user_agent(ua: &str) -> Self { Self::new(Platform::detect_from_user_agent(ua)) }

    pub fn request_permission(&mut self, cap: Capability) -> Result<bool, OmniError> {
        if !self.platform.has_capability(cap) {
            return Err(OmniError::Unsupported(format!("{:?} not available on {:?}", cap, self.platform)));
        }
        if !self.granted_permissions.contains(&cap) { self.granted_permissions.push(cap); }
        Ok(true)
    }

    pub fn has_permission(&self, cap: Capability) -> bool { self.granted_permissions.contains(&cap) }

    /// Negotiate features: return what both client and server support
    pub fn negotiate(&self, server_features: &[&str], client_features: &[&str]) -> Vec<String> {
        server_features.iter().filter(|f| client_features.contains(f)).map(|f| f.to_string()).collect()
    }

    pub fn set_feature(&mut self, name: &str, enabled: bool) { self.features.insert(name.into(), enabled); }
    pub fn is_feature_enabled(&self, name: &str) -> bool { self.features.get(name).copied().unwrap_or(false) }
    pub fn platform(&self) -> Platform { self.platform }

    /// Generate capability report
    pub fn capability_report(&self) -> Vec<(String, bool)> {
        let all_caps = [Capability::Camera, Capability::Microphone, Capability::Gps, Capability::Bluetooth,
            Capability::Nfc, Capability::Haptic, Capability::Gyroscope, Capability::Lidar,
            Capability::FaceId, Capability::Biometric, Capability::WebTransport, Capability::WebGpu];
        all_caps.iter().map(|c| (format!("{:?}", c), self.platform.has_capability(*c))).collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_detect_android() { assert_eq!(Platform::detect_from_user_agent("Mozilla/5.0 (Linux; Android 14)"), Platform::Android); }
    #[test]
    fn test_detect_ios() { assert_eq!(Platform::detect_from_user_agent("Mozilla/5.0 (iPhone; CPU iPhone OS)"), Platform::Ios); }
    #[test]
    fn test_ios_has_lidar() { assert!(Platform::Ios.has_capability(Capability::Lidar)); }
    #[test]
    fn test_android_no_lidar() { assert!(!Platform::Android.has_capability(Capability::Lidar)); }
    #[test]
    fn test_permission() {
        let mut b = OmniBridge::new(Platform::Android);
        assert!(b.request_permission(Capability::Camera).is_ok());
        assert!(b.has_permission(Capability::Camera));
        assert!(b.request_permission(Capability::Lidar).is_err());
    }
    #[test]
    fn test_negotiate() {
        let b = OmniBridge::new(Platform::Web);
        let common = b.negotiate(&["webtransport", "webrtc", "quic"], &["webrtc", "webtransport"]);
        assert_eq!(common, vec!["webtransport", "webrtc"]);
    }
}
