//! CI configuration file parsing.
//!
//! Loads `.gitlab-ci.yml` and `.github/workflows/*.yml` files into
//! [`crate::model::RawPipeline`] values. Handles system-specific features:
//!
//! - **GitLab** -- `include:` (local, remote, project, template), `!reference`
//!   tags, deep merge, YAML anchors/aliases.
//! - **GitHub** -- workflow files, `matrix:` expansion, `${{ }}` expression
//!   interpolation, reusable workflow inputs.

pub mod github;
pub mod gitlab;
pub(crate) mod merge;

// Re-export GitLab parser as default for now
pub use gitlab::fetch as gitlab_fetch;
pub use gitlab::{parse_pipeline_file, parse_pipeline_file_with_root};

/// Maximum size of a YAML document that will be parsed (10 MB).
/// Prevents memory exhaustion from YAML anchor/alias bombs or
/// excessively large CI configuration files.
pub(crate) const MAX_YAML_SIZE: usize = 10 * 1024 * 1024;

/// Check that a YAML input is within the size limit before parsing.
/// Returns an error with a descriptive message if the input is too large.
pub(crate) fn check_yaml_size(content: &str, source: &str) -> anyhow::Result<()> {
    if content.len() > MAX_YAML_SIZE {
        anyhow::bail!(
            "YAML input too large ({} bytes, limit {} bytes) in {}",
            content.len(),
            MAX_YAML_SIZE,
            source
        );
    }
    Ok(())
}

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

    #[test]
    fn test_check_yaml_size_within_limit() {
        assert!(check_yaml_size("small content", "test.yml").is_ok());
    }

    #[test]
    fn test_check_yaml_size_exact_limit() {
        let content = "x".repeat(MAX_YAML_SIZE);
        assert!(check_yaml_size(&content, "test.yml").is_ok());
    }

    #[test]
    fn test_check_yaml_size_exceeds_limit() {
        let content = "x".repeat(MAX_YAML_SIZE + 1);
        let result = check_yaml_size(&content, "big.yml");
        assert!(result.is_err());
        let err = result.unwrap_err().to_string();
        assert!(err.contains("too large"), "unexpected error: {}", err);
        assert!(err.contains("big.yml"), "should mention source: {}", err);
    }

    #[test]
    fn test_check_yaml_size_empty() {
        assert!(check_yaml_size("", "empty.yml").is_ok());
    }

    #[test]
    fn test_max_yaml_size_constant() {
        assert_eq!(MAX_YAML_SIZE, 10 * 1024 * 1024);
    }
}
