// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::error::PowerManagerError;
use crate::message::{Message, MessageReturn};
use anyhow::format_err;
use async_trait::async_trait;
use futures::future::join_all;
use std::rc::Rc;

/// A trait that all nodes in the PowerManager must implement
#[async_trait(?Send)]
pub trait Node {
    /// Return a string to indicate the name of this node
    ///
    /// Each node should use this function to indicate a meaningful name. The name may be used for
    /// logging and/or debugging purposes.
    fn name(&self) -> String;

    /// Handle a new message
    ///
    /// All nodes must implement this message to support communication between nodes. This is the
    /// entry point for a Node to receive new messages.
    async fn handle_message(&self, _msg: &Message) -> Result<MessageReturn, PowerManagerError> {
        Err(PowerManagerError::Unsupported)
    }

    /// Send a message to another node
    ///
    /// This is implemented as a future to support scenarios where a node wishes to send messages to
    /// multiple other nodes. Errors are logged automatically.
    async fn send_message(
        &self,
        node: &Rc<dyn Node>,
        msg: &Message,
    ) -> Result<MessageReturn, PowerManagerError> {
        // TODO(fxbug.dev/44484): Ideally we'd use a duration event here. But due to a limitation in
        // the Rust tracing library, that would require creating any formatted strings (such as the
        // "message" value) unconditionally, even when the tracing category is disabled. To avoid
        // that unnecessary computation, just use an instant event.
        fuchsia_trace::instant!(
            "power_manager:messages",
            "message_start",
            fuchsia_trace::Scope::Thread,
            "message" => format!("{:?}", msg).as_str(),
            "source_node" => self.name().as_str(),
            "dest_node" => node.name().as_str()
        );

        let result = node.handle_message(msg).await;
        fuchsia_trace::instant!(
            "power_manager:messages",
            "message_result",
            fuchsia_trace::Scope::Thread,
            "message" => format!("{:?}", msg).as_str(),
            "source_node" => self.name().as_str(),
            "dest_node" => node.name().as_str(),
            "result" => format!("{:?}", result).as_str()
        );
        result
    }

    /// Send a message to a list of other nodes. The message is sent to each node in a separate
    /// Future and all are joined before returning. The results from all nodes are returned in a
    /// vector in the same node-ordering that was provided.
    async fn send_message_to_many(
        &self,
        nodes: &Vec<Rc<dyn Node>>,
        msg: &Message,
    ) -> Vec<Result<MessageReturn, PowerManagerError>> {
        join_all(nodes.iter().map(|node| async move {
            self.send_message(node, msg).await.map_err(|e| {
                PowerManagerError::GenericError(format_err!(
                    "Failed to send message to {}: {}",
                    node.name(),
                    e
                ))
            })
        }))
        .await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test::mock_node::{MessageMatcher, MockNodeMaker};
    use crate::{msg_eq, msg_ok_return};
    use assert_matches::assert_matches;
    use fuchsia_async as fasync;

    struct TestNode;
    impl Node for TestNode {
        fn name(&self) -> String {
            "TestNode".to_string()
        }
    }

    /// Tests that `send_message_to_many` sends a message to all provided nodes and the results are
    /// returned correctly.
    #[fasync::run_singlethreaded(test)]
    async fn test_send_message_to_many() {
        let mut mock_maker = MockNodeMaker::new();
        let sending_node = mock_maker.make("sending_node", vec![]);

        let receiving_node_1 = mock_maker.make(
            "receiving_node_1",
            vec![(msg_eq!(GetPerformanceState), msg_ok_return!(GetPerformanceState(1)))],
        );
        let receiving_node_2 = mock_maker.make(
            "receiving_node_1",
            vec![(msg_eq!(GetPerformanceState), msg_ok_return!(GetPerformanceState(2)))],
        );

        let results = sending_node
            .send_message_to_many(
                &vec![receiving_node_1, receiving_node_2],
                &Message::GetPerformanceState,
            )
            .await;

        assert_eq!(results.len(), 2);
        assert_matches!(results[0], Ok(MessageReturn::GetPerformanceState(1)));
        assert_matches!(results[1], Ok(MessageReturn::GetPerformanceState(2)));
    }
}
