lcpfs 2026.1.102

LCP File System - A ZFS-inspired copy-on-write filesystem for Rust
// Copyright 2025 LunaOS Contributors
// SPDX-License-Identifier: Apache-2.0

//! Storage Analytics Module.
//!
//! Provides detailed storage usage metrics, performance statistics,
//! and capacity planning insights for LCPFS datasets.

extern crate alloc;

mod metrics;
mod reports;
mod types;

pub use metrics::*;
pub use reports::*;
pub use types::*;

use alloc::string::String;
use alloc::vec::Vec;
use spin::Mutex;

/// Global analytics collector
static ANALYTICS_COLLECTOR: Mutex<Option<AnalyticsCollector>> = Mutex::new(None);

/// Initialize the analytics subsystem
pub fn init() {
    let mut collector = ANALYTICS_COLLECTOR.lock();
    if collector.is_none() {
        *collector = Some(AnalyticsCollector::new());
    }
}

/// Storage Analytics API
pub struct Analytics;

impl Analytics {
    /// Get storage usage summary for a dataset
    pub fn usage_summary(dataset: &str) -> Result<UsageSummary, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_usage_summary(dataset)
    }

    /// Get detailed space breakdown
    pub fn space_breakdown(dataset: &str) -> Result<SpaceBreakdown, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_space_breakdown(dataset)
    }

    /// Get I/O performance statistics
    pub fn io_stats(dataset: &str) -> Result<IoStats, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_io_stats(dataset)
    }

    /// Get capacity forecast
    pub fn capacity_forecast(dataset: &str, days: u32) -> Result<CapacityForecast, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.forecast_capacity(dataset, days)
    }

    /// Get top space consumers
    pub fn top_consumers(
        dataset: &str,
        limit: usize,
    ) -> Result<Vec<SpaceConsumer>, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_top_consumers(dataset, limit)
    }

    /// Get file type distribution
    pub fn file_type_distribution(dataset: &str) -> Result<Vec<FileTypeStats>, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_file_type_distribution(dataset)
    }

    /// Get deduplication statistics
    pub fn dedup_stats(dataset: &str) -> Result<DedupStats, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_dedup_stats(dataset)
    }

    /// Get compression statistics
    pub fn compression_stats(dataset: &str) -> Result<CompressionStats, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_compression_stats(dataset)
    }

    /// Get snapshot space usage
    pub fn snapshot_usage(dataset: &str) -> Result<SnapshotUsage, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_snapshot_usage(dataset)
    }

    /// Record a data point for trending
    pub fn record_data_point(dataset: &str, metric: MetricType, value: u64) {
        if let Some(ref mut collector) = *ANALYTICS_COLLECTOR.lock() {
            collector.record_metric(dataset, metric, value);
        }
    }

    /// Get historical trend data
    pub fn get_trend(
        dataset: &str,
        metric: MetricType,
        period: TrendPeriod,
    ) -> Result<Vec<TrendPoint>, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.get_trend(dataset, metric, period)
    }

    /// Generate a full analytics report
    pub fn full_report(dataset: &str) -> Result<FullReport, AnalyticsError> {
        let collector = ANALYTICS_COLLECTOR.lock();
        let collector = collector.as_ref().ok_or(AnalyticsError::NotInitialized)?;

        collector.generate_full_report(dataset)
    }
}

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

    #[test]
    fn test_init() {
        init();
        let collector = ANALYTICS_COLLECTOR.lock();
        assert!(collector.is_some());
    }
}