// Copyright 2024 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::{Incoming, Node};
use fuchsia_async::ScopeHandle;
use fuchsia_component::server::{ServiceFs, ServiceObjTrait};
use fuchsia_component_config::Config;
use fuchsia_inspect::Inspector;
use inspect_runtime::PublishOptions;
use log::error;
use namespace::Namespace;
use zx::Status;

use fdf::DispatcherRef;
use fidl_fuchsia_driver_framework::DriverStartArgs;

/// The context arguments passed to the driver in its start arguments.
pub struct DriverContext {
    /// A reference to the root [`fdf::Dispatcher`] for this driver.
    pub root_dispatcher: DispatcherRef<'static>,
    /// The original [`DriverStartArgs`] passed in as start arguments, minus any parts that were
    /// used to construct other elements of [`Self`].
    pub start_args: DriverStartArgs,
    /// The incoming namespace constructed from [`DriverStartArgs::incoming`]. Since producing this
    /// consumes the incoming namespace from [`Self::start_args`], that will always be [`None`].
    pub incoming: Incoming,
    #[doc(hidden)]
    _private: (),
}

impl DriverContext {
    /// Binds the node proxy client end from the start args into a [`NodeProxy`] that can be used
    /// to add child nodes. Dropping this proxy will result in the node being removed and the
    /// driver starting shutdown, so it should be bound and stored in your driver object in its
    /// [`crate::Driver::start`] method.
    ///
    /// After calling this, [`DriverStartArgs::node`] in [`Self::start_args`] will be `None`.
    ///
    /// Returns [`Status::INVALID_ARGS`] if the node client end is not present in the start
    /// arguments.
    pub fn take_node(&mut self) -> Result<Node, Status> {
        let node_client = self.start_args.node.take().ok_or(Status::INVALID_ARGS)?;
        Ok(Node::from(node_client.into_proxy()))
    }

    /// Returns the component config.
    ///
    /// After calling this, [`DriverStartArgs::config`] in [`Self::start_args`] will be `None`.
    ///
    /// Returns [`Status::INVALID_ARGS`] if the config is not present in the start arguments.
    pub fn take_config<C: Config>(&mut self) -> Result<C, Status> {
        let vmo = self.start_args.config.take().ok_or(Status::INVALID_ARGS)?;
        Ok(Config::from_vmo(&vmo).expect("Config VMO handle must be valid."))
    }

    /// Serves the given [`ServiceFs`] on the node's outgoing directory. This can only be called
    /// once, and after this the [`DriverStartArgs::outgoing_dir`] member will be [`None`].
    ///
    /// Logs an error and returns [`Status::INVALID_ARGS`] if the outgoing directory server end is
    /// not present in the start arguments, or [`Status::INTERNAL`] if serving the connection
    /// failed.
    pub fn serve_outgoing<O: ServiceObjTrait>(
        &mut self,
        outgoing_fs: &mut ServiceFs<O>,
    ) -> Result<(), Status> {
        let Some(outgoing_dir) = self.start_args.outgoing_dir.take() else {
            error!("Tried to serve on outgoing directory but it wasn't available");
            return Err(Status::INVALID_ARGS);
        };
        outgoing_fs.serve_connection(outgoing_dir).map_err(|err| {
            error!("Failed to serve outgoing directory: {err}");
            Status::INTERNAL
        })?;

        Ok(())
    }

    /// Spawns a server handling `fuchsia.inspect.Tree` requests and a handle
    /// to the `fuchsia.inspect.Tree` is published using `fuchsia.inspect.InspectSink`.
    ///
    /// Whenever the client wishes to stop publishing Inspect, the Controller may be dropped.
    pub fn publish_inspect(&self, inspector: &Inspector, scope: ScopeHandle) -> Result<(), Status> {
        let client = self.incoming.connect_protocol().map_err(|err| {
            error!("Error connecting to inspect : {err}");
            Status::INTERNAL
        })?;

        let task = inspect_runtime::publish(
            inspector,
            PublishOptions::default().on_inspect_sink_client(client),
        )
        .ok_or(Status::INTERNAL)?;

        scope.spawn_local(task);

        Ok(())
    }

    pub(crate) fn new(
        root_dispatcher: DispatcherRef<'static>,
        mut start_args: DriverStartArgs,
    ) -> Result<Self, Status> {
        let incoming_namespace: Namespace = start_args
            .incoming
            .take()
            .unwrap_or_else(|| vec![])
            .try_into()
            .map_err(|_| Status::INVALID_ARGS)?;
        let incoming = incoming_namespace.try_into().map_err(|_| Status::INVALID_ARGS)?;
        Ok(DriverContext { root_dispatcher, start_args, incoming, _private: () })
    }

    pub(crate) fn start_logging(&self, driver_name: &str) -> Result<(), Status> {
        let log_client = match self.incoming.connect_protocol() {
            Ok(log_client) => log_client,
            Err(err) => {
                eprintln!("Error connecting to log sink proxy at driver startup: {err}. Continuing without logging.");
                return Ok(());
            }
        };

        if let Err(e) = diagnostics_log::initialize(
            diagnostics_log::PublishOptions::default()
                .use_log_sink(log_client)
                .tags(&["driver", driver_name]),
        ) {
            eprintln!("Error initializing logging at driver startup: {e}");
        }
        Ok(())
    }
}
