use crate::sketchbook::model::ModelState;
use biodivine_hctl_model_checker::preprocessing::hctl_tree::HctlTreeNode;
use biodivine_hctl_model_checker::preprocessing::parser::{
    parse_and_minimize_hctl_formula, parse_hctl_formula,
};
use biodivine_lib_param_bn::symbolic_async_graph::SymbolicContext;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct HctlFormula {
    #[serde(
        serialize_with = "serialize_tree",
        deserialize_with = "deserialize_tree"
    )]
    tree: HctlTreeNode,
}
pub fn parse_hctl_formula_wrapper(formula: &str) -> Result<HctlTreeNode, String> {
    parse_hctl_formula(formula)
        .map_err(|e| format!("Error during HCTL formula processing: '{}'", e))
}
pub fn parse_and_minimize_hctl_formula_wrapper(
    symbolic_context: &SymbolicContext,
    formula: &str,
) -> Result<HctlTreeNode, String> {
    parse_and_minimize_hctl_formula(symbolic_context, formula)
        .map_err(|e| format!("Error during HCTL formula processing: '{}'", e))
}
fn serialize_tree<S>(tree: &HctlTreeNode, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    serializer.serialize_str(&tree.to_string())
}
fn deserialize_tree<'de, D>(deserializer: D) -> Result<HctlTreeNode, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    parse_hctl_formula_wrapper(&s).map_err(de::Error::custom)
}
impl fmt::Display for HctlFormula {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.tree)
    }
}
impl HctlFormula {
    pub fn try_from_str(formula: &str) -> Result<HctlFormula, String> {
        Ok(HctlFormula {
            tree: parse_hctl_formula_wrapper(formula)?,
        })
    }
}
impl HctlFormula {
    pub fn change_formula(&mut self, new_formula: &str) -> Result<(), String> {
        self.tree = parse_hctl_formula_wrapper(new_formula)?;
        Ok(())
    }
}
impl HctlFormula {
    pub fn as_str(&self) -> &str {
        &self.tree.formula_str
    }
    pub fn tree(&self) -> &HctlTreeNode {
        &self.tree
    }
}
impl HctlFormula {
    pub fn check_syntax(formula: &str) -> Result<(), String> {
        let res = parse_hctl_formula_wrapper(formula);
        if res.is_ok() {
            Ok(())
        } else {
            Err(res.err().unwrap())
        }
    }
    pub fn check_syntax_with_model(formula: &str, model: &ModelState) -> Result<(), String> {
        let bn = model.to_empty_bn();
        let ctx = SymbolicContext::new(&bn)?;
        let res: Result<HctlTreeNode, String> =
            parse_and_minimize_hctl_formula_wrapper(&ctx, formula);
        if res.is_ok() {
            Ok(())
        } else {
            Err(res.err().unwrap())
        }
    }
}