turbovault_tools/
export_tools.rs

1//! Export tools for vault analysis data
2
3use std::sync::Arc;
4use turbovault_core::prelude::*;
5use turbovault_export::{
6    AnalysisReportExporter, BrokenLinkRecord, BrokenLinksExporter, HealthReportExporter,
7    VaultStatsExporter, VaultStatsRecord, create_health_report,
8};
9use turbovault_parser::to_plain_text;
10use turbovault_vault::VaultManager;
11
12/// Export tools for vault analysis and reporting
13pub struct ExportTools {
14    pub manager: Arc<VaultManager>,
15}
16
17impl ExportTools {
18    /// Create new export tools
19    pub fn new(manager: Arc<VaultManager>) -> Self {
20        Self { manager }
21    }
22
23    /// Export health report
24    pub async fn export_health_report(&self, format: &str) -> Result<String> {
25        let graph = self.manager.link_graph();
26        let graph_read = graph.read().await;
27
28        let stats = graph_read.stats();
29
30        // Calculate metrics
31        let total_notes = stats.total_files;
32        let total_links = stats.total_links;
33        let broken_links = 0; // Would need HealthAnalyzer for actual count
34        let orphaned_notes = stats.orphaned_files;
35
36        // Health score heuristic
37        let health_score = if broken_links == 0 && orphaned_notes == 0 {
38            100
39        } else if broken_links == 0 {
40            80
41        } else {
42            70
43        };
44
45        let report = create_health_report(
46            "default",
47            health_score,
48            total_notes,
49            total_links,
50            broken_links,
51            orphaned_notes,
52        );
53
54        match format {
55            "json" => HealthReportExporter::to_json(&report),
56            "csv" => HealthReportExporter::to_csv(&report),
57            _ => Err(Error::config_error(
58                "Invalid export format. Use 'json' or 'csv'".to_string(),
59            )),
60        }
61    }
62
63    /// Export broken links
64    pub async fn export_broken_links(&self, format: &str) -> Result<String> {
65        // In real implementation, would get actual broken links from HealthAnalyzer
66        let links: Vec<BrokenLinkRecord> = vec![];
67
68        match format {
69            "json" => BrokenLinksExporter::to_json(&links),
70            "csv" => BrokenLinksExporter::to_csv(&links),
71            _ => Err(Error::config_error(
72                "Invalid export format. Use 'json' or 'csv'".to_string(),
73            )),
74        }
75    }
76
77    /// Export vault statistics
78    pub async fn export_vault_stats(&self, format: &str) -> Result<String> {
79        let graph = self.manager.link_graph();
80        let graph_read = graph.read().await;
81        let stats = graph_read.stats();
82
83        // Calculate readability metrics by scanning all markdown files
84        let files = self.manager.scan_vault().await?;
85        let mut total_words = 0usize;
86        let mut total_readable_chars = 0usize;
87        let mut note_count = 0usize;
88
89        for file_path in &files {
90            if !file_path.to_string_lossy().to_lowercase().ends_with(".md") {
91                continue;
92            }
93            if let Ok(vault_file) = self.manager.parse_file(file_path).await {
94                let plain_text = to_plain_text(&vault_file.content);
95                total_words += plain_text.split_whitespace().count();
96                total_readable_chars += plain_text.chars().count();
97                note_count += 1;
98            }
99        }
100
101        let avg_words_per_note = if note_count > 0 {
102            total_words as f64 / note_count as f64
103        } else {
104            0.0
105        };
106
107        let stats_record = VaultStatsRecord {
108            timestamp: chrono::Utc::now().to_rfc3339(),
109            vault_name: "default".to_string(),
110            total_files: stats.total_files,
111            total_links: stats.total_links,
112            orphaned_files: stats.orphaned_files,
113            average_links_per_file: stats.average_links_per_file,
114            total_words,
115            total_readable_chars,
116            avg_words_per_note,
117        };
118
119        match format {
120            "json" => VaultStatsExporter::to_json(&stats_record),
121            "csv" => VaultStatsExporter::to_csv(&stats_record),
122            _ => Err(Error::config_error(
123                "Invalid export format. Use 'json' or 'csv'".to_string(),
124            )),
125        }
126    }
127
128    /// Export full analysis report
129    pub async fn export_analysis_report(&self, format: &str) -> Result<String> {
130        let graph = self.manager.link_graph();
131        let graph_read = graph.read().await;
132        let stats = graph_read.stats();
133
134        let total_notes = stats.total_files;
135        let total_links = stats.total_links;
136        let broken_links = 0;
137        let orphaned_notes = stats.orphaned_files;
138
139        let health_score = if broken_links == 0 && orphaned_notes == 0 {
140            100
141        } else if broken_links == 0 {
142            80
143        } else {
144            70
145        };
146
147        let health = create_health_report(
148            "default",
149            health_score,
150            total_notes,
151            total_links,
152            broken_links,
153            orphaned_notes,
154        );
155
156        let analysis_report = turbovault_export::AnalysisReport {
157            timestamp: chrono::Utc::now().to_rfc3339(),
158            vault_name: "default".to_string(),
159            health,
160            broken_links_count: broken_links,
161            orphaned_notes_count: orphaned_notes,
162            recommendations: vec![
163                "Ensure all notes are linked for better connectivity".to_string(),
164                "Review and fix broken links regularly".to_string(),
165            ],
166        };
167
168        match format {
169            "json" => AnalysisReportExporter::to_json(&analysis_report),
170            "csv" => AnalysisReportExporter::to_csv(&analysis_report),
171            _ => Err(Error::config_error(
172                "Invalid export format. Use 'json' or 'csv'".to_string(),
173            )),
174        }
175    }
176}