//! Log information to help with network diagnostics.
//!
//! This is meant for troubleshooting problems in the VM, when there is no
//! direct hands-on access to its insides.

use serde::{Deserialize, Serialize};

use crate::{
    action::{ActionError, Context},
    action_impl::{spawn, ActionImpl},
};

/// Upload build artifacts using `rsync` to configured server.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NetworkdDiagnostics {}

impl ActionImpl for NetworkdDiagnostics {
    fn execute(&self, context: &mut Context) -> Result<(), ActionError> {
        network_diagnostics(context);
        Ok(())
    }
}

/// Wait for network to be online.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct WaitOnline {}

impl ActionImpl for WaitOnline {
    fn execute(&self, context: &mut Context) -> Result<(), ActionError> {
        // This assumes Linux with systemd. Later on, we'll want to make this more generic.
        spawn(
            context,
            &["systemctl", "start", "systemd-networkd-wait-online"],
        )?;
        spawn(
            context,
            &["systemctl", "status", "systemd-networkd-wait-online"],
        )?;

        network_diagnostics(context);
        Ok(())
    }
}

fn network_diagnostics(context: &mut Context) {
    // This assumes Linux with systemd. Later on, we'll want to make this more generic.
    // Also note that we intentionally ignore any errors: failing a run when diagnostic
    // queries fail is not good.
    spawn(context, &["systemctl", "status", "systemd-networkd"]).ok();
    spawn(
        context,
        &["systemctl", "status", "systemd-networkd-wait-online"],
    )
    .ok();
    spawn(
        context,
        &["systemctl", "show", "systemd-networkd-wait-online"],
    )
    .ok();

    // Do we have network set up?
    spawn(context, &["ip", "address"]).ok();

    // `networkctl` is from systemd.
    spawn(context, &["networkctl", "list"]).ok();
    spawn(context, &["networkctl", "status"]).ok();

    // Can we reach the DNS server provided by Google?
    spawn(context, &["ping", "-c1", "8.8.8.8"]).ok();

    // Can we ping a host by name? This checks that DNS works.
    spawn(context, &["ping", "-c1", "www.google.com"]).ok();
}

/// Errors from `NetworkDiagnostics` action.
#[derive(Debug, thiserror::Error)]
pub enum DiagnotsticsError {}
