// Copyright 2020 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::model::{
        error::ModelError,
        exposed_dir::ExposedDir,
        hooks::{Event, EventError, EventErrorPayload, EventPayload, RuntimeInfo},
        namespace::IncomingNamespace,
        realm::{BindReason, ExecutionState, Package, Realm, Runtime, WeakRealm},
        runner::Runner,
    },
    cm_rust::data,
    fidl::endpoints::{self, Proxy, ServerEnd},
    fidl_fuchsia_component_runner as fcrunner,
    fidl_fuchsia_io::DirectoryProxy,
    fuchsia_async as fasync, fuchsia_zircon as zx,
    log::*,
    moniker::AbsoluteMoniker,
    std::sync::Arc,
    vfs::execution_scope::ExecutionScope,
};

pub(super) async fn do_start(
    realm: &Arc<Realm>,
    bind_reason: &BindReason,
) -> Result<(), ModelError> {
    // Pre-flight check: if the component is already started, return now. Note that `bind_at` also
    // performs this check before scheduling the action; here, we do it again while the action is
    // registered so we avoid the risk of invoking the BeforeStart hook twice.
    {
        let execution = realm.lock_execution().await;
        if let Some(res) = should_return_early(&execution, &realm.abs_moniker) {
            return res;
        }
    }

    struct StartContext {
        component_decl: cm_rust::ComponentDecl,
        resolved_url: String,
        runner: Arc<dyn Runner>,
        pending_runtime: Runtime,
        start_info: fcrunner::ComponentStartInfo,
        controller_server_end: ServerEnd<fcrunner::ComponentControllerMarker>,
    }

    let result = async move {
        // Resolve the component.
        let component = realm.resolve().await?;

        // Find the runner to use.
        let runner = realm.resolve_runner().await.map_err(|e| {
            error!("Failed to resolve runner for `{}`: {}", realm.abs_moniker, e);
            e
        })?;

        // Generate the Runtime which will be set in the Execution.
        let (pending_runtime, start_info, controller_server_end) = make_execution_runtime(
            realm.as_weak(),
            component.resolved_url.clone(),
            component.package,
            &component.decl,
        )
        .await?;

        Ok(StartContext {
            component_decl: component.decl,
            resolved_url: component.resolved_url.clone(),
            runner,
            pending_runtime,
            start_info,
            controller_server_end,
        })
    }
    .await;

    let mut start_context = match result {
        Ok(start_context) => {
            let event = Event::new_with_timestamp(
                realm,
                Ok(EventPayload::Started {
                    realm: realm.into(),
                    runtime: RuntimeInfo::from_runtime(
                        &start_context.pending_runtime,
                        start_context.resolved_url.clone(),
                    ),
                    component_decl: start_context.component_decl.clone(),
                    bind_reason: bind_reason.clone(),
                }),
                start_context.pending_runtime.timestamp,
            );

            realm.hooks.dispatch(&event).await?;
            start_context
        }
        Err(e) => {
            let event = Event::new(realm, Err(EventError::new(&e, EventErrorPayload::Started)));
            realm.hooks.dispatch(&event).await?;
            return Err(e);
        }
    };

    // Set the Runtime in the Execution. From component manager's perspective, this indicates
    // that the component has started. This may return early if the component is shut down.
    {
        let mut execution = realm.lock_execution().await;
        if let Some(res) = should_return_early(&execution, &realm.abs_moniker) {
            return res;
        }
        start_context.pending_runtime.watch_for_exit(realm.as_weak());
        execution.runtime = Some(start_context.pending_runtime);
    }

    // It's possible that the component is stopped before getting here. If so, that's fine: the
    // runner will start the component, but its stop or kill signal will be immediately set on the
    // component controller.
    start_context.runner.start(start_context.start_info, start_context.controller_server_end).await;

    Ok(())
}

/// Returns `Some(Result)` if `bind` should return early based on either of the following:
/// - The component instance is shut down.
/// - The component instance is already started.
pub fn should_return_early(
    execution: &ExecutionState,
    abs_moniker: &AbsoluteMoniker,
) -> Option<Result<(), ModelError>> {
    if execution.is_shut_down() {
        Some(Err(ModelError::instance_shut_down(abs_moniker.clone())))
    } else if execution.runtime.is_some() {
        Some(Ok(()))
    } else {
        None
    }
}

/// Returns a configured Runtime for a component and the start info (without actually starting
/// the component).
async fn make_execution_runtime(
    realm: WeakRealm,
    url: String,
    package: Option<Package>,
    decl: &cm_rust::ComponentDecl,
) -> Result<
    (Runtime, fcrunner::ComponentStartInfo, ServerEnd<fcrunner::ComponentControllerMarker>),
    ModelError,
> {
    // Create incoming/outgoing directories, and populate them.
    let exposed_dir = ExposedDir::new(ExecutionScope::new(), realm.clone(), decl.clone())?;
    let (outgoing_dir_client, outgoing_dir_server) =
        zx::Channel::create().map_err(|e| ModelError::namespace_creation_failed(e))?;
    let (runtime_dir_client, runtime_dir_server) =
        zx::Channel::create().map_err(|e| ModelError::namespace_creation_failed(e))?;
    let mut namespace = IncomingNamespace::new(package)?;
    let ns = namespace.populate(realm, decl).await?;

    let (controller_client, controller_server) =
        endpoints::create_endpoints::<fcrunner::ComponentControllerMarker>()
            .expect("could not create component controller endpoints");
    let controller =
        controller_client.into_proxy().expect("failed to create ComponentControllerProxy");
    // Set up channels into/out of the new component. These are absent from non-executable
    // components.
    let outgoing_dir_client = decl.get_used_runner().map(|_| {
        DirectoryProxy::from_channel(fasync::Channel::from_channel(outgoing_dir_client).unwrap())
    });
    let runtime_dir_client = decl.get_used_runner().map(|_| {
        DirectoryProxy::from_channel(fasync::Channel::from_channel(runtime_dir_client).unwrap())
    });
    let runtime = Runtime::start_from(
        Some(namespace),
        outgoing_dir_client,
        runtime_dir_client,
        exposed_dir,
        Some(controller),
    )?;
    let start_info = fcrunner::ComponentStartInfo {
        resolved_url: Some(url),
        program: data::clone_option_dictionary(&decl.program),
        ns: Some(ns),
        outgoing_dir: Some(ServerEnd::new(outgoing_dir_server)),
        runtime_dir: Some(ServerEnd::new(runtime_dir_server)),
        ..fcrunner::ComponentStartInfo::EMPTY
    };

    Ok((runtime, start_info, controller_server))
}
