//! Real compose functionality for apt-ostree
//! 
//! This module provides the main entry point for tree composition,
//! integrating package management, OSTree operations, and container generation.

pub mod treefile;
pub mod composer;
pub mod package_manager;
pub mod ostree_integration;
pub mod container;

use std::path::PathBuf;
use apt_ostree::lib::error::{AptOstreeError, AptOstreeResult};
use treefile::Treefile;
use composer::TreeComposer;

/// Main entry point for tree composition
pub async fn compose_tree(
    treefile_path: &str,
    repo_path: Option<&str>,
    options: &ComposeOptions,
) -> AptOstreeResult<String> {
    println!("Starting apt-ostree tree composition...");
    
    // Parse treefile
    let treefile = Treefile::parse_treefile(treefile_path).await?;
    println!("Treefile parsed successfully: {}", treefile.metadata.ref_name);
    
    // Create tree composer
    let composer = TreeComposer::new(options)?;
    
    // Compose the tree
    let commit_hash = composer.compose_tree(&treefile).await?;
    
    println!("Tree composition completed successfully!");
    println!("Reference: {}", treefile.metadata.ref_name);
    println!("Commit: {}", commit_hash);
    
    Ok(commit_hash)
}

/// Options for tree composition
#[derive(Debug, Clone)]
pub struct ComposeOptions {
    /// Working directory for the composition process
    pub workdir: Option<PathBuf>,
    /// OSTree repository path
    pub repo: Option<String>,
    /// Whether to generate container images
    pub generate_container: bool,
    /// Whether to keep build artifacts
    pub keep_artifacts: bool,
    /// Whether to run in verbose mode
    pub verbose: bool,
    /// Whether to run in dry-run mode
    pub dry_run: bool,
    /// Maximum number of parallel package installations
    pub max_parallel: Option<usize>,
    /// Whether to skip package verification
    pub skip_verification: bool,
    /// Whether to force rebuild
    pub force_rebuild: bool,
    /// Parent reference for incremental builds
    pub parent: Option<String>,
    /// Output format for container images
    pub output_format: Option<String>,
    /// Whether to generate static deltas
    pub generate_deltas: bool,
    /// Whether to compress the repository
    pub compress_repo: bool,
    /// Whether to sign commits
    pub sign_commits: bool,
    /// GPG key for signing
    pub gpg_key: Option<String>,
    /// Whether to validate the tree after composition
    pub validate_tree: bool,
    /// Whether to run tests after composition
    pub run_tests: bool,
    /// Whether to generate documentation
    pub generate_docs: bool,
    /// Whether to create a summary report
    pub create_summary: bool,
}

impl Default for ComposeOptions {
    fn default() -> Self {
        Self {
            workdir: None,
            repo: None,
            generate_container: false,
            keep_artifacts: false,
            verbose: false,
            dry_run: false,
            max_parallel: Some(4),
            skip_verification: false,
            force_rebuild: false,
            parent: None,
            output_format: Some("docker-archive".to_string()),
            generate_deltas: false,
            compress_repo: true,
            sign_commits: false,
            gpg_key: None,
            validate_tree: true,
            run_tests: false,
            generate_docs: false,
            create_summary: true,
        }
    }
}

impl ComposeOptions {
    /// Create a new ComposeOptions instance with default values
    pub fn new() -> Self {
        Self::default()
    }
    
    /// Set the working directory
    pub fn workdir(mut self, workdir: PathBuf) -> Self {
        self.workdir = Some(workdir);
        self
    }
    
    /// Set the OSTree repository path
    pub fn repo(mut self, repo: String) -> Self {
        self.repo = Some(repo);
        self
    }
    
    /// Enable container image generation
    pub fn generate_container(mut self) -> Self {
        self.generate_container = true;
        self
    }
    
    /// Enable verbose output
    pub fn verbose(mut self) -> Self {
        self.verbose = true;
        self
    }
    
    /// Enable dry-run mode
    pub fn dry_run(mut self) -> Self {
        self.dry_run = true;
        self
    }
    
    /// Set maximum parallel package installations
    pub fn max_parallel(mut self, max: usize) -> Self {
        self.max_parallel = Some(max);
        self
    }
    
    /// Set parent reference for incremental builds
    pub fn parent(mut self, parent: String) -> Self {
        self.parent = Some(parent);
        self
    }
    
    /// Set output format for container images
    pub fn output_format(mut self, format: String) -> Self {
        self.output_format = Some(format);
        self
    }
    
    /// Enable static delta generation
    pub fn generate_deltas(mut self) -> Self {
        self.generate_deltas = true;
        self
    }
    
    /// Enable commit signing
    pub fn sign_commits(mut self, gpg_key: String) -> Self {
        self.sign_commits = true;
        self.gpg_key = Some(gpg_key);
        self
    }
    
    /// Enable tree validation
    pub fn validate_tree(mut self) -> Self {
        self.validate_tree = true;
        self
    }
    
    /// Enable test execution
    pub fn run_tests(mut self) -> Self {
        self.run_tests = true;
        self
    }
    
    /// Enable documentation generation
    pub fn generate_docs(mut self) -> Self {
        self.generate_docs = true;
        self
    }
    
    /// Create a summary report
    pub fn create_summary(mut self) -> Self {
        self.create_summary = true;
        self
    }
}

/// Builder for ComposeOptions
pub struct ComposeOptionsBuilder {
    options: ComposeOptions,
}

impl ComposeOptionsBuilder {
    /// Create a new builder with default options
    pub fn new() -> Self {
        Self {
            options: ComposeOptions::default(),
        }
    }
    
    /// Set the working directory
    pub fn workdir(mut self, workdir: PathBuf) -> Self {
        self.options.workdir = Some(workdir);
        self
    }
    
    /// Set the OSTree repository path
    pub fn repo(mut self, repo: String) -> Self {
        self.options.repo = Some(repo);
        self
    }
    
    /// Enable container image generation
    pub fn generate_container(mut self) -> Self {
        self.options.generate_container = true;
        self
    }
    
    /// Enable verbose output
    pub fn verbose(mut self) -> Self {
        self.options.verbose = true;
        self
    }
    
    /// Enable dry-run mode
    pub fn dry_run(mut self) -> Self {
        self.options.dry_run = true;
        self
    }
    
    /// Set maximum parallel package installations
    pub fn max_parallel(mut self, max: usize) -> Self {
        self.options.max_parallel = Some(max);
        self
    }
    
    /// Set parent reference for incremental builds
    pub fn parent(mut self, parent: String) -> Self {
        self.options.parent = Some(parent);
        self
    }
    
    /// Set output format for container images
    pub fn output_format(mut self, format: String) -> Self {
        self.options.output_format = Some(format);
        self
    }
    
    /// Enable static delta generation
    pub fn generate_deltas(mut self) -> Self {
        self.options.generate_deltas = true;
        self
    }
    
    /// Enable commit signing
    pub fn sign_commits(mut self, gpg_key: String) -> Self {
        self.options.sign_commits = true;
        self.options.gpg_key = Some(gpg_key);
        self
    }
    
    /// Enable tree validation
    pub fn validate_tree(mut self) -> Self {
        self.options.validate_tree = true;
        self
    }
    
    /// Enable test execution
    pub fn run_tests(mut self) -> Self {
        self.options.run_tests = true;
        self
    }
    
    /// Enable documentation generation
    pub fn generate_docs(mut self) -> Self {
        self.options.generate_docs = true;
        self
    }
    
    /// Create a summary report
    pub fn create_summary(mut self) -> Self {
        self.options.create_summary = true;
        self
    }
    
    /// Build the final ComposeOptions
    pub fn build(self) -> ComposeOptions {
        self.options
    }
}

impl Default for ComposeOptionsBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Utility functions for tree composition
pub mod utils {
    use super::*;
    
    /// Validate a treefile before composition
    pub async fn validate_treefile(treefile: &Treefile) -> AptOstreeResult<()> {
        println!("Validating treefile...");
        
        // Check required fields
        if treefile.metadata.ref_name.is_empty() {
            return Err(AptOstreeError::System("Treefile must specify a reference name".to_string()));
        }
        
        if treefile.repositories.is_empty() {
            return Err(AptOstreeError::System("Treefile must specify at least one repository".to_string()));
        }
        
        // Check package configuration
        if let Some(packages) = &treefile.packages.base {
            if packages.is_empty() {
                return Err(AptOstreeError::System("Base packages list cannot be empty".to_string()));
            }
        }
        
        println!("✅ Treefile validation passed");
        Ok(())
    }
    
    /// Create a simple treefile for testing
    pub fn create_test_treefile() -> Treefile {
        Treefile {
            api_version: "1.0".to_string(),
            kind: "tree".to_string(),
            metadata: treefile::TreefileMetadata {
                ref_name: "apt-ostree/test/debian/trixie".to_string(),
                version: Some("1.0.0".to_string()),
                description: Some("Test Debian Trixie tree".to_string()),
                timestamp: Some(chrono::Utc::now().to_rfc3339()),
                parent: None,
            },
            base_image: Some("debian:trixie".to_string()),
            repositories: vec![
                treefile::Repository {
                    name: "debian".to_string(),
                    url: "http://deb.debian.org/debian".to_string(),
                    suite: "trixie".to_string(),
                    components: vec!["main".to_string(), "contrib".to_string(), "non-free".to_string()],
                    enabled: true,
                    gpg_key: None,
                }
            ],
            packages: treefile::PackageConfig {
                base: Some(vec!["systemd".to_string(), "bash".to_string(), "coreutils".to_string()]),
                additional: Some(vec!["curl".to_string(), "wget".to_string()]),
                excludes: None,
            },
            customizations: None,
            output: Some(treefile::OutputConfig {
                generate_container: true,
                container_path: Some("test-image.tar".to_string()),
                export_formats: vec!["docker-archive".to_string()],
            }),
        }
    }
    
    /// Print composition progress
    pub fn print_progress(step: &str, current: usize, total: usize) {
        let percentage = (current as f64 / total as f64) * 100.0;
        println!("[{}%] {} ({}/{})", percentage as i32, step, current, total);
    }
    
    /// Print composition summary
    pub fn print_summary(commit_hash: &str, ref_name: &str, workdir: &PathBuf) {
        println!("\n=== Composition Summary ===");
        println!("✅ Tree composition completed successfully");
        println!("Reference: {}", ref_name);
        println!("Commit: {}", commit_hash);
        println!("Working directory: {}", workdir.display());
        println!("===========================\n");
    }
}
