// Copyright 2018 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 {
    anyhow::{format_err, Context as _, Error},
    fidl_fuchsia_netemul_environment::ManagedEnvironmentMarker,
    fidl_fuchsia_netemul_sync::{BusMarker, BusProxy, Event, SyncManagerMarker},
    fuchsia_async as fasync,
    fuchsia_component::client,
    fuchsia_zircon as zx,
    futures::TryStreamExt,
    structopt::StructOpt,
};

#[derive(StructOpt, Debug)]
struct Opt {
    #[structopt(short = "f")]
    fail: bool,
    #[structopt(short = "n", default_value = "root")]
    name: String,
    #[structopt(short = "w")]
    wait: Option<u64>,
    #[structopt(short = "p")]
    publish: Option<i32>,
    #[structopt(short = "e")]
    event: Option<i32>,
    #[structopt(short = "P")]
    check_path: Option<String>,
    #[structopt(short = "s")]
    service: Option<String>,
    #[structopt(short = "l")]
    log: Option<String>,
}

const BUS_NAME: &str = "test-bus";

pub struct BusConnection {
    bus: BusProxy,
}

impl BusConnection {
    pub fn new(client: &str) -> Result<BusConnection, Error> {
        let busm = client::connect_to_service::<SyncManagerMarker>()
            .context("SyncManager not available")?;
        let (bus, busch) = fidl::endpoints::create_proxy::<BusMarker>()?;
        busm.bus_subscribe(BUS_NAME, client, busch)?;
        Ok(BusConnection { bus })
    }

    pub async fn publish_code(&self, code: i32) -> Result<(), Error> {
        let () = self
            .bus
            .ensure_publish(Event {
                code: Some(code),
                message: None,
                arguments: None,
                ..Event::EMPTY
            })
            .await?;
        Ok(())
    }

    pub async fn wait_for_event(&self, code: i32) -> Result<(), Error> {
        let mut stream = self.bus.take_event_stream().try_filter_map(|event| match event {
            fidl_fuchsia_netemul_sync::BusEvent::OnBusData { data } => match data.code {
                Some(rcv_code) => {
                    if rcv_code == code {
                        futures::future::ok(Some(()))
                    } else {
                        futures::future::ok(None)
                    }
                }
                None => futures::future::ok(None),
            },
            _ => futures::future::ok(None),
        });
        stream.try_next().await?;
        Ok(())
    }

    pub async fn perform_bus_ops(
        &self,
        publish: Option<i32>,
        wait: Option<i32>,
    ) -> Result<(), Error> {
        if let Some(code) = wait {
            let () = self.wait_for_event(code).await?;
        }
        if let Some(code) = publish {
            let () = self.publish_code(code).await?;
        }
        Ok(())
    }
}

#[fasync::run_singlethreaded]
async fn main() -> Result<(), Error> {
    let opt = Opt::from_args();

    // Attempt to connect to the bus early on so that we do not miss any events.
    //
    // We won't actually unwrap `bus` until later in case this
    // test does not actually need the bus.
    let bus = BusConnection::new(&opt.name);

    if let Some(log) = opt.log {
        println!("Initing syslog...");
        let () = fuchsia_syslog::init().context("cannot init logger")?;

        println!("Logging to syslog: {}", log);
        log::info!("{}", log);
    }

    if let Some(svc) = opt.service {
        println!("Connecting to service [{}]...", svc);
        let env = client::connect_to_service::<ManagedEnvironmentMarker>()?;
        let (_dummy, server) = zx::Channel::create()?;
        env.connect_to_service(&svc, server)?;
    }

    if let Some(wait) = opt.wait {
        println!("Sleeping for {}...", wait);
        std::thread::sleep(std::time::Duration::from_millis(wait));
    }

    if let Some(path) = opt.check_path {
        println!("Checking path existence {}...", &path);
        if !std::path::Path::new(&path).exists() {
            return Err(format_err!("{} is not in namespace", &path));
        }
    }

    if opt.publish != None || opt.event != None {
        // Unwrap the `bus` which should be an error
        // if the test requires publish or event waiting operations.
        let bus = bus.context("Failed to connect to bus")?;

        println!("Publishing: {:?} | Waiting for event: {:?}", opt.publish, opt.event);
        let () = bus.perform_bus_ops(opt.publish, opt.event).await?;
    }

    if opt.fail {
        Err(format_err!("Failing because was asked to."))
    } else {
        println!("All done!");
        Ok(())
    }
}
