use std::{fs, path::Path};

use rngpui_craby_codegen::types::Schema;
use rngpui_craby_common::constants::{crate_dir, HASH_COMMENT_PREFIX};
use log::debug;

/// Validate the schema(s) by comparing the hash in the `generated.rs` file
///
/// If the hash does not match, it will bail with an error
/// In this case, you need to re-generate the `generated.rs` file by `codegen` command
pub fn validate_schema(project_root: &Path, schemas: &[Schema]) -> anyhow::Result<()> {
    let src = fs::read_to_string(crate_dir(project_root).join("src").join("generated.rs"))?;

    match get_hash_from_src(&src) {
        Some(src_hash) => {
            let curr_hash = Schema::to_hash(schemas);
            debug!("Current hash: {:#?}, Expected hash: {:#?}, ", curr_hash, src_hash);
            if src_hash != curr_hash {
                anyhow::bail!("Generated hash does not match the hash in the `generated.rs` file (current: {}, expected: {})", curr_hash, src_hash);
            }
            Ok(())
        }
        None => anyhow::bail!("Hash not found in the `generated.rs` file. Please run `crabygen` to generate the file."),
    }
}

/// Get the hash from the `generated.rs` file
///
/// # Example
///
/// ```rust,ignore
/// // Hash: xxx
/// ```
///
/// # Returns
///
/// The hash string (eg. `xxx`)
fn get_hash_from_src(src: &str) -> Option<String> {
    let comment = src
        .lines()
        .find(|line| line.trim().starts_with(HASH_COMMENT_PREFIX));

    if let Some(comment) = comment {
        let hash = comment
            .trim()
            .split(HASH_COMMENT_PREFIX)
            .nth(1)
            .map(|hash| hash.trim().to_string());

        return hash.filter(|hash| !hash.is_empty());
    }

    None
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_get_hash_from_src() {
        let src = r#"
        // Auto generated by Craby. DO NOT EDIT.
        // Hash: 1234567890
        pub struct Foo {}
        "#;
        let hash = get_hash_from_src(src);
        assert_eq!(hash, Some("1234567890".to_string()));
    }
}
