use std::path::Path;
use serde::{Deserialize, Deserializer};
use serde_state::DeserializeState;
use necsim_impls_std::event_log::recorder::EventLogConfig;
use crate::args::{
    config::{
        partitioning::Partitioning,
        pause::Pause,
        sample::{Sample, SampleMode},
    },
    utils::parse::try_parse_state,
};
use super::super::BufferingSimulateArgsBuilder;
pub(in super::super) fn parse_and_normalise(
    ron_args: &str,
    normalised_args: &mut BufferingSimulateArgsBuilder,
    partitioning: &Partitioning,
    sample: &Sample,
    pause: &Option<Pause>,
) -> anyhow::Result<Option<EventLogConfig>> {
    let mut event_log_check = partitioning.get_event_log_check();
    if event_log_check.0.is_ok() && (pause.is_some() || !matches!(sample.mode, SampleMode::Genesis))
    {
        event_log_check.0 = Err(anyhow::anyhow!(
            "Pausing or resuming a simulation requires an event log"
        ));
    }
    let SimulateArgsEventLogOnly { event_log } =
        try_parse_state("simulate", ron_args, &mut event_log_check)?;
    normalised_args.log(&event_log);
    let event_log = match event_log {
        Some(event_log)
            if event_log.directory() == Path::new("I-solemnly-swear-that-I-am-up-to-no-good") =>
        {
            None
        },
        event_log => event_log,
    };
    Ok(event_log)
}
struct SimulateArgsEventLogOnly {
    event_log: Option<EventLogConfig>,
}
impl<'de> DeserializeState<'de, (anyhow::Result<()>, anyhow::Result<()>)>
    for SimulateArgsEventLogOnly
{
    fn deserialize_state<D>(
        event_log_check: &mut (anyhow::Result<()>, anyhow::Result<()>),
        deserializer: D,
    ) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        let raw = SimulateArgsEventLogOnlyRaw::deserialize_state(event_log_check, deserializer)?;
        if raw.event_log.is_none() {
            event_log_check
                .0
                .as_ref()
                .map_err(serde::de::Error::custom)?;
        } else {
            event_log_check
                .1
                .as_ref()
                .map_err(serde::de::Error::custom)?;
        }
        Ok(SimulateArgsEventLogOnly {
            event_log: raw.event_log,
        })
    }
}
#[derive(DeserializeState)]
#[serde(deserialize_state = "(anyhow::Result<()>, anyhow::Result<()>)")]
#[serde(rename = "Simulate")]
struct SimulateArgsEventLogOnlyRaw {
    #[serde(alias = "log")]
    #[serde(default)]
    #[serde(deserialize_state_with = "deserialize_state_event_log")]
    event_log: Option<EventLogConfig>,
}
fn deserialize_state_event_log<'de, D: Deserializer<'de>>(
    event_log_check: &mut (anyhow::Result<()>, anyhow::Result<()>),
    deserializer: D,
) -> Result<Option<EventLogConfig>, D::Error> {
    let maybe_event_log = <Option<EventLogConfig>>::deserialize(deserializer)?;
    if maybe_event_log.is_none() {
        event_log_check
            .0
            .as_ref()
            .map_err(serde::de::Error::custom)?;
    } else {
        event_log_check
            .1
            .as_ref()
            .map_err(serde::de::Error::custom)?;
    }
    Ok(maybe_event_log)
}