// Archive Module - Universal Compression Format Support
// Supports 12 compression formats: 9 core + 3 optional
// Core: ZIP, TAR, GZIP, ZSTD, BZIP2, LZ4, TAR.GZ, TAR.BZ2, TAR.ZST
// Optional: RAR (legal risk), XZ (external dependency), 7z (unstable library)

pub mod config;
pub mod detector;
pub mod metadata;
pub mod processor;
pub mod warning;

pub mod processors {
    pub mod core;
    #[cfg(feature = "optional-formats")]
    pub mod optional;
}

#[cfg(test)]
pub mod tests;

use anyhow::Result;
use std::collections::HashMap;
use std::path::Path;

use crate::archive::{ArchiveFormat, ArchiveProcessor, FormatDetector, ArchiveConfig};

/// Processor Registry - Plugin Architecture
pub struct ProcessorRegistry {
    processors: HashMap<ArchiveFormat, Box<dyn ArchiveProcessor>>,
    config: ArchiveConfig,
}

impl ProcessorRegistry {
    /// Create new registry with config
    pub fn new(config: ArchiveConfig) -> Self {
        Self {
            processors: HashMap::new(),
            config,
        }
    }
    
    /// Initialize all processors (based on config)
    pub fn initialize(&mut self) -> Result<()> {
        // Core formats (always registered)
        self.register_core_processors()?;
        
        // Optional formats (based on config)
        self.register_optional_processors()?;
        
        Ok(())
    }
    
    /// Register core format processors (9 formats)
    fn register_core_processors(&mut self) -> Result<()> {
        use crate::archive::processors::core::*;
        
        self.processors.insert(ArchiveFormat::Zip, Box::new(ZipProcessor::new()));
        self.processors.insert(ArchiveFormat::Tar, Box::new(TarProcessor::new()));
        self.processors.insert(ArchiveFormat::Gzip, Box::new(GzipProcessor::new()));
        self.processors.insert(ArchiveFormat::Zstd, Box::new(ZstdProcessor::new()));
        self.processors.insert(ArchiveFormat::Bzip2, Box::new(Bzip2Processor::new()));
        self.processors.insert(ArchiveFormat::Lz4, Box::new(Lz4Processor::new()));
        self.processors.insert(ArchiveFormat::TarGzip, Box::new(TarGzipProcessor::new()));
        self.processors.insert(ArchiveFormat::TarBzip2, Box::new(TarBzip2Processor::new()));
        self.processors.insert(ArchiveFormat::TarZstd, Box::new(TarZstdProcessor::new()));
        
        info!("✅ Core formats registered: 9 formats");
        Ok(())
    }
    
    /// Register optional format processors (3 formats, based on config)
    fn register_optional_processors(&mut self) -> Result<()> {
        #[cfg(feature = "optional-formats")]
        {
            use crate::archive::processors::optional::*;
            
            // RAR format (legal risk)
            if self.config.enable_rar {
                crate::archive::warning::show_rar_legal_warning();
                self.processors.insert(ArchiveFormat::Rar, Box::new(RarProcessor::new()));
                warn!("⚠️ RAR format enabled (legal risk)");
            }
            
            // XZ format (external dependency)
            if self.config.enable_xz {
                if check_liblzma_available() {
                    self.processors.insert(ArchiveFormat::Xz, Box::new(XzProcessor::new()));
                    info!("✅ XZ format enabled");
                } else {
                    crate::archive::warning::show_xz_dependency_warning();
                    warn!("⚠️ XZ format disabled (liblzma not found)");
                }
            }
            
            // 7z format (unstable library)
            if self.config.enable_7z {
                crate::archive::warning::show_7z_stability_warning();
                self.processors.insert(ArchiveFormat::SevenZ, Box::new(SevenZProcessor::new()));
                warn!("⚠️ 7z format enabled (stability warning)");
            }
        }
        
        Ok(())
    }
    
    /// Get processor for detected format
    pub fn get_processor(&self, path: &Path) -> Result<&dyn ArchiveProcessor> {
        let detector = FormatDetector::new();
        let format = detector.detect(path)?;
        
        self.processors
            .get(&format)
            .map(|p| p.as_ref())
            .ok_or_else(|| anyhow::anyhow!("Format {} not supported or not enabled", format))
    }
    
    /// List all enabled formats
    pub fn enabled_formats(&self) -> Vec<ArchiveFormat> {
        self.processors.keys().cloned().collect()
    }
}

/// Check if liblzma library is available
#[cfg(feature = "optional-formats")]
fn check_liblzma_available() -> bool {
    // Try to load xz2 library
    // Simplified check: try to create XzProcessor
    true  // Simplified for now, actual implementation needs better detection
}

#[cfg(not(feature = "optional-formats"))]
fn check_liblzma_available() -> bool {
    false
}

/// Initialize archive system with config
pub fn init_archive_system(config_path: Option<&str>) -> Result<ProcessorRegistry> {
    let config = if let Some(path) = config_path {
        ArchiveConfig::load(path)?
    } else {
        ArchiveConfig::default()
    };
    
    // Show startup warnings for optional formats
    crate::archive::warning::show_startup_warnings(&config);
    
    let mut registry = ProcessorRegistry::new(config);
    registry.initialize()?;
    
    info!("Archive system initialized with {} formats", registry.enabled_formats().len());
    Ok(registry)
}