convergio-reports 0.1.7

Convergio Think Tank — professional research report generation service
Documentation
//! CTT branding templates and formatting.

use chrono::Utc;

use crate::types::ReportType;

pub const CTT_BRAND: &str = "Convergio Think Tank";
pub const CTT_SHORT: &str = "CTT";

pub const DISCLAIMER: &str = "\
This report was generated by Convergio Think Tank using AI-powered research \
and analysis. While all data points are sourced from publicly available \
information and cross-verified where possible, AI-generated content may \
contain inaccuracies. This report is provided for informational purposes \
only and does not constitute professional advice. Always verify critical \
information independently.\n\n\
© Convergio Think Tank. All rights reserved.";

/// Format the report header block.
pub fn format_header(topic: &str, report_type: ReportType, date: &str) -> String {
    format!(
        "# {CTT_BRAND}\n\
         ## {label}\n\n\
         **Subject:** {topic}\n\
         **Report Date:** {date}\n\
         **Data Cutoff:** {date}\n\n\
         ---\n",
        label = report_type.label(),
    )
}

/// Format the report footer with branding and page reference.
pub fn format_footer(topic: &str, date: &str) -> String {
    format!(
        "\n---\n\n\
         *{CTT_SHORT} | {topic} | {date} | CONFIDENTIAL*\n"
    )
}

/// Format the full disclaimer section.
pub fn format_disclaimer() -> String {
    format!(
        "\n---\n\n\
         ## Disclaimer\n\n\
         {DISCLAIMER}\n"
    )
}

/// Format the sources section from a list of URLs.
pub fn format_sources(sources: &[String]) -> String {
    if sources.is_empty() {
        return "\n## Sources & Methodology\n\nNo sources consulted.\n".to_string();
    }
    let mut out = String::from("\n## Sources & Methodology\n\n");
    for (i, url) in sources.iter().enumerate() {
        out.push_str(&format!("[{}] {}\n\n", i + 1, url));
    }
    out
}

/// Current date formatted for reports.
pub fn report_date() -> String {
    Utc::now().format("%d %B %Y").to_string()
}

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

    #[test]
    fn header_contains_brand() {
        let h = format_header("Test Topic", ReportType::General, "01 January 2026");
        assert!(h.contains(CTT_BRAND));
        assert!(h.contains("Test Topic"));
        assert!(h.contains("General Research"));
    }

    #[test]
    fn footer_contains_ctt() {
        let f = format_footer("Test", "01 January 2026");
        assert!(f.contains(CTT_SHORT));
        assert!(f.contains("CONFIDENTIAL"));
    }

    #[test]
    fn disclaimer_not_empty() {
        let d = format_disclaimer();
        assert!(d.contains("AI-powered"));
        assert!(d.contains("informational purposes"));
    }

    #[test]
    fn sources_numbered() {
        let s = format_sources(&[
            "https://example.com/a".into(),
            "https://example.com/b".into(),
        ]);
        assert!(s.contains("[1]"));
        assert!(s.contains("[2]"));
    }

    #[test]
    fn date_format_valid() {
        let d = report_date();
        assert!(!d.is_empty());
    }
}