stout 0.2.0

A fast, Rust-based Homebrew-compatible package manager
//! Analytics command - manage opt-in usage analytics
//!
//! stout respects user privacy. Analytics are:
//! - Completely opt-in (disabled by default)
//! - Anonymous (no personally identifiable information)
//! - Transparent (you can see what's collected)

use anyhow::Result;
use stout_state::{Config, Paths};
use clap::{Args as ClapArgs, Subcommand};
use console::style;

#[derive(ClapArgs)]
pub struct Args {
    #[command(subcommand)]
    pub command: Option<AnalyticsCommand>,
}

#[derive(Subcommand)]
pub enum AnalyticsCommand {
    /// Enable anonymous usage analytics
    On,

    /// Disable usage analytics
    Off,

    /// Show current analytics status
    Status,

    /// Show what data would be collected
    What,
}

pub async fn run(args: Args) -> Result<()> {
    match args.command {
        Some(AnalyticsCommand::On) => run_on().await,
        Some(AnalyticsCommand::Off) => run_off().await,
        Some(AnalyticsCommand::Status) | None => run_status().await,
        Some(AnalyticsCommand::What) => run_what().await,
    }
}

async fn run_on() -> Result<()> {
    let paths = Paths::default();
    let mut config = Config::load(&paths)?;

    config.analytics.enabled = true;
    config.save(&paths)?;

    println!(
        "\n{} Analytics enabled\n",
        style("").green().bold()
    );

    println!("Thank you for helping improve stout!");
    println!("Run '{}' to see what data is collected.\n", style("stout analytics what").cyan());

    Ok(())
}

async fn run_off() -> Result<()> {
    let paths = Paths::default();
    let mut config = Config::load(&paths)?;

    config.analytics.enabled = false;
    config.save(&paths)?;

    println!(
        "\n{} Analytics disabled\n",
        style("").green().bold()
    );

    Ok(())
}

async fn run_status() -> Result<()> {
    let paths = Paths::default();
    let config = Config::load(&paths)?;

    println!("\n{}\n", style("Analytics Status").cyan().bold());

    if config.analytics.enabled {
        println!(
            "  Status: {}",
            style("Enabled").green()
        );
        println!("\n  Run '{}' to disable.", style("stout analytics off").cyan());
    } else {
        println!(
            "  Status: {}",
            style("Disabled").dim()
        );
        println!("\n  Run '{}' to enable.", style("stout analytics on").cyan());
    }

    println!("  Run '{}' to see what data is collected.\n", style("stout analytics what").cyan());

    Ok(())
}

async fn run_what() -> Result<()> {
    println!("\n{}\n", style("What stout collects (when enabled)").cyan().bold());

    println!("{}:", style("Anonymous usage data").bold());
    println!("  • Commands used (install, search, update, etc.)");
    println!("  • Package names installed/searched");
    println!("  • stout version");
    println!("  • Operating system and architecture");
    println!("  • Success/failure status of operations");
    println!();

    println!("{}:", style("What we DO NOT collect").bold());
    println!("  • IP addresses (not logged)");
    println!("  • User identifiers");
    println!("  • File paths or contents");
    println!("  • Custom tap information");
    println!("  • Environment variables");
    println!("  • Any personal information");
    println!();

    println!("{}:", style("Why we collect this").bold());
    println!("  • Understand which packages are most popular");
    println!("  • Identify common errors to fix");
    println!("  • Prioritize development efforts");
    println!();

    println!("{}:", style("Data handling").bold());
    println!("  • Data is aggregated and anonymized");
    println!("  • No individual usage is tracked");
    println!("  • You can disable at any time with '{}'\n", style("stout analytics off").cyan());

    Ok(())
}

/// Record an analytics event (only if analytics are enabled)
pub async fn record_event(event_type: &str, data: &str) -> Result<()> {
    let paths = Paths::default();
    let config = Config::load(&paths)?;

    if !config.analytics.enabled {
        return Ok(());
    }

    // In a real implementation, this would send data to an analytics endpoint
    // For now, we just log locally for debugging
    #[cfg(debug_assertions)]
    {
        tracing::debug!("Analytics event: {} - {}", event_type, data);
    }

    // NOTE: Analytics posting is intentionally disabled by default
    // This feature would require user opt-in and a dedicated analytics endpoint
    // Uncomment below to enable in development:
    //
    // let client = reqwest::Client::new();
    // let _ = client.post("https://analytics.stout.dev/v1/events")
    //     .json(&serde_json::json!({
    //         "event": event_type,
    //         "data": data,
    //         "version": env!("CARGO_PKG_VERSION"),
    //         "os": std::env::consts::OS,
    //         "arch": std::env::consts::ARCH,
    //     }))
    //     .send()
    //     .await;

    Ok(())
}

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

    #[test]
    fn test_analytics_command_variants() {
        // Verify all command variants exist
        let _on = AnalyticsCommand::On;
        let _off = AnalyticsCommand::Off;
        let _status = AnalyticsCommand::Status;
        let _what = AnalyticsCommand::What;
    }

    #[tokio::test]
    async fn test_record_event_disabled() {
        // When analytics are disabled, record_event should return Ok
        // This test just verifies it doesn't panic
        let result = record_event("test", "data").await;
        // Should succeed (either enabled or disabled)
        assert!(result.is_ok() || result.is_err());
    }
}