use crate::ast::*;
use crate::transform::TransformCtx;
use serde::{Deserialize, Deserializer, Serialize};
use std::fs::File;
use std::path::Path;
#[derive(Serialize, Deserialize)]
#[serde(rename = "Crate")]
pub struct CrateData {
    #[serde(deserialize_with = "ensure_version")]
    pub charon_version: String,
    pub translated: TranslatedCrate,
    #[serde(skip)]
    pub has_errors: bool,
}
impl CrateData {
    pub fn new(ctx: &TransformCtx) -> Self {
        CrateData {
            charon_version: crate::VERSION.to_owned(),
            translated: ctx.translated.clone(),
            has_errors: ctx.has_errors(),
        }
    }
    #[allow(clippy::result_unit_err)]
    pub fn serialize_to_file(&self, target_filename: &Path) -> Result<(), ()> {
        let target_dir = target_filename.parent().unwrap();
        match std::fs::create_dir_all(target_dir) {
            Ok(()) => (),
            Err(_) => {
                error!("Could not create the directory: {:?}", target_dir);
                return Err(());
            }
        };
        let std::io::Result::Ok(outfile) = File::create(target_filename) else {
            error!("Could not open: {:?}", target_filename);
            return Err(());
        };
        match serde_json::to_writer(&outfile, self) {
            Ok(()) => {}
            Err(err) => {
                error!("Could not write to `{target_filename:?}`: {err:?}");
                return Err(());
            }
        }
        let target_filename = std::fs::canonicalize(target_filename).unwrap();
        if self.has_errors {
            info!(
                "Generated the partial (because we encountered errors) file: {}",
                target_filename.to_str().unwrap()
            );
        } else {
            info!("Generated the file: {}", target_filename.to_str().unwrap());
        }
        Ok(())
    }
}
fn ensure_version<'de, D: Deserializer<'de>>(d: D) -> Result<String, D::Error> {
    use serde::de::Error;
    let version = String::deserialize(d)?;
    if version != crate::VERSION {
        return Err(D::Error::custom(format!(
            "Incompatible version of charon: \
            this program supports llbc emitted by charon v{} \
            but attempted to read a file emitted by charon v{}",
            crate::VERSION,
            version,
        )));
    }
    Ok(version)
}