// Copyright (C) 2023 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 management system for request services.
//!
//! This module provides central management of network connectivity for the
//! request service, including network state monitoring and communication with
//! the task manager.

use std::mem::MaybeUninit;
use std::sync::{Mutex, Once};

use super::network::{NetworkInner, NetworkState};
use super::task_manager::TaskManagerTx;
use crate::manage::network::Network;
use crate::utils::call_once;

/// Central manager for network connectivity and state monitoring.
///
/// Manages the network state and provides an interface for the task manager to
/// communicate with the network system.
///
/// # Fields
///
/// * `network` - The underlying network interface used to monitor connectivity
/// * `tx` - Optional channel to send messages to the task manager
pub(crate) struct NetworkManager {
    pub(crate) network: Network,
    pub(crate) tx: Option<TaskManagerTx>,
}

impl NetworkManager {
    /// Returns the singleton instance of the network manager.
    ///
    /// Uses lazy initialization with thread-safe synchronization to ensure only
    /// one instance is created during program execution.
    ///
    /// # Safety
    ///
    /// Uses unsafe code to access the static mutable variable, but ensures
    /// thread safety through proper synchronization with `Once` and
    /// `Mutex`.
    ///
    /// # Returns
    ///
    /// Returns a static reference to a `Mutex<NetworkManager>` that can be
    /// locked to access the network manager instance.
    pub(crate) fn get_instance() -> &'static Mutex<NetworkManager> {
        static mut NETWORK_MANAGER: MaybeUninit<Mutex<NetworkManager>> = MaybeUninit::uninit();
        static ONCE: Once = Once::new();

        unsafe {
            call_once(&ONCE, || {
                // Create the network interface and initialize the network manager
                let inner = NetworkInner::new();
                let network = Network {
                    inner,
                    _registry: None,
                };
                let network_manager = NetworkManager { network, tx: None };
                NETWORK_MANAGER.write(Mutex::new(network_manager));
            });
            &*NETWORK_MANAGER.as_ptr()
        }
    }

    /// Checks if the device is currently online.
    ///
    /// # Returns
    ///
    /// Returns `true` if the network is in an `Online` state, otherwise
    /// `false`.
    ///
    /// # Panics
    ///
    /// Panics if the mutex cannot be locked, which typically indicates a
    /// deadlock.
    pub(crate) fn is_online() -> bool {
        let network_manager = NetworkManager::get_instance().lock().unwrap();
        matches!(network_manager.network.state(), NetworkState::Online(_))
    }

    /// Queries the current network state.
    ///
    /// # Returns
    ///
    /// Returns the current `NetworkState` of the network interface.
    ///
    /// # Panics
    ///
    /// Panics if the mutex cannot be locked, which typically indicates a
    /// deadlock.
    pub(super) fn query_network() -> NetworkState {
        let network_manager = NetworkManager::get_instance().lock().unwrap();
        network_manager.network.state()
    }
}