// Copyright (C) 2025 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Network observer wrapper and C++ FFI interface.
//! 
//! This module provides a safe Rust wrapper around the C++ network observation
//! system. It defines the `NetObserverWrapper` that bridges between the C++
//! network events and Rust observers, as well as the FFI interface needed for
//! interop.

use std::sync::{Arc, Mutex};

use ffi::{NetInfo, NetUnregistration};

use super::Observer;

/// Wrapper that adapts Rust network observers to the C++ network event system.
///
/// `NetObserverWrapper` holds a collection of Rust observers and forwards
/// network events received from C++ to all registered observers.
pub struct NetObserverWrapper {
    /// Shared collection of observers to receive network event notifications.
    inner: Arc<Mutex<Vec<Box<dyn Observer>>>>,
}

impl NetObserverWrapper {
    /// Creates a new network observer wrapper with the given collection of observers.
    pub fn new(inner: Arc<Mutex<Vec<Box<dyn Observer>>>>) -> Self {
        Self { inner }
    }
}

impl NetObserverWrapper {
    /// Notifies all observers when a network becomes available.
    ///
    /// # Arguments
    ///
    /// * `net_id` - Identifier of the newly available network
    ///
    /// # Panics
    ///
    /// Panics if the mutex for the observer list is poisoned.
    pub(crate) fn net_available(&self, net_id: i32) {
        let inner = self.inner.lock().unwrap();
        for observer in inner.iter() {
            observer.net_available(net_id);
        }
    }

    /// Notifies all observers when a network is lost.
    ///
    /// # Arguments
    ///
    /// * `net_id` - Identifier of the network that was lost
    ///
    /// # Panics
    ///
    /// Panics if the mutex for the observer list is poisoned.
    pub(crate) fn net_lost(&self, net_id: i32) {
        let inner = self.inner.lock().unwrap();
        for observer in inner.iter() {
            observer.net_lost(net_id);
        }
    }

    /// Notifies all observers when network capabilities change.
    ///
    /// # Arguments
    ///
    /// * `net_id` - Identifier of the network whose capabilities changed
    /// * `net_info` - Updated network information containing new capabilities
    ///
    /// # Panics
    ///
    /// Panics if the mutex for the observer list is poisoned.
    pub(crate) fn net_capability_changed(&self, net_id: i32, net_info: NetInfo) {
        let inner = self.inner.lock().unwrap();
        for observer in inner.iter() {
            observer.net_capability_changed(net_id, &net_info);
        }
    }
}

/// Safety: `NetUnregistration` is safe to send between threads as it
/// doesn't contain any thread-local state.
unsafe impl Send for NetUnregistration {}

/// Safety: `NetUnregistration` can be shared between threads as its
/// unregister method is thread-safe.
unsafe impl Sync for NetUnregistration {}

// C++ FFI bridge for network observation
#[cxx::bridge(namespace = "OHOS::Request")]
pub mod ffi {
    // Network capability types from the NetManagerStandard namespace
    #[namespace = "OHOS::NetManagerStandard"]
    #[derive(Debug)]
    #[repr(i32)]
    enum NetCap {
        NET_CAPABILITY_MMS = 0,
        NET_CAPABILITY_SUPL = 1,
        NET_CAPABILITY_DUN = 2,
        NET_CAPABILITY_IA = 3,
        NET_CAPABILITY_XCAP = 4,
        NET_CAPABILITY_BIP = 5,
        NET_CAPABILITY_NOT_METERED = 11,
        NET_CAPABILITY_INTERNET = 12,
        NET_CAPABILITY_NOT_VPN = 15,
        NET_CAPABILITY_VALIDATED = 16,
        NET_CAPABILITY_PORTAL = 17,
        NET_CAPABILITY_INTERNAL_DEFAULT = 18,
        NET_CAPABILITY_CHECKING_CONNECTIVITY = 31,
        NET_CAPABILITY_END = 32,
    }

    // Network bearer types from the NetManagerStandard namespace
    #[namespace = "OHOS::NetManagerStandard"]
    #[derive(Debug)]
    #[repr(i32)]
    enum NetBearType {
        BEARER_CELLULAR = 0,
        BEARER_WIFI = 1,
        BEARER_BLUETOOTH = 2,
        BEARER_ETHERNET = 3,
        BEARER_VPN = 4,
        BEARER_WIFI_AWARE = 5,
        BEARER_DEFAULT,
    }

    /// Network information containing capabilities and bearer types.
    #[derive(Debug)]
    struct NetInfo {
        /// List of capabilities supported by the network.
        caps: Vec<NetCap>,
        /// Types of network bearers available.
        bear_types: Vec<NetBearType>,
    }

    // Rust functions exposed to C++
    extern "Rust" {
        type NetObserverWrapper;

        fn net_available(&self, net_id: i32);
        fn net_lost(&self, net_id: i32);
        fn net_capability_changed(&self, net_id: i32, net_info: NetInfo);
    }

    // C++ functions and types exposed to Rust
    unsafe extern "C++" {
        include!("net_all_capabilities.h");
        include!("request_utils_network.h");

        #[namespace = "OHOS::NetManagerStandard"]
        type NetCap;
        #[namespace = "OHOS::NetManagerStandard"]
        type NetBearType;

        type NetUnregistration;
        /// Unregisters the network observer from the system.
        fn unregister(self: &NetUnregistration) -> i32;

        /// Registers a network observer with the system.
        ///
        /// Returns a unique pointer to a NetUnregistration object that can be
        /// used to unregister the observer later.
        #[allow(unused)]
        fn RegisterNetObserver(
            wrapper: Box<NetObserverWrapper>,
            error: &mut i32,
        ) -> UniquePtr<NetUnregistration>;
    }
}