//! Remote asset fetching and management system

use rustelo_core::{Result, RusteloError};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};

/// Remote asset source configuration
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RemoteAssetSource {
    pub base_url: String,
    pub template_variant: Option<String>,
    pub cache_enabled: bool,
    pub cache_ttl_hours: u64,
    pub cache_directory: PathBuf,
    pub fallback_to_embedded: bool,
    pub requirements_check: bool,
}

/// Template metadata from remote source
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TemplateManifest {
    pub name: String,
    pub description: String,
    pub version: String,
    pub requirements: TemplateRequirements,
    pub features: Vec<String>,
    pub files: Vec<TemplateFile>,
    pub variables: HashMap<String, TemplateVariable>,
}

/// Template requirements that must be checked
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TemplateRequirements {
    pub node_version: Option<String>,
    pub rust_version: Option<String>,
    pub system_dependencies: Vec<String>,
    pub optional_dependencies: Vec<String>,
    pub framework_features: Vec<String>,
    pub minimum_disk_space_mb: Option<u64>,
    pub supported_platforms: Vec<String>,
}

/// Template file information
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TemplateFile {
    pub path: String,
    pub source_path: String,
    pub is_template: bool,
    pub is_executable: bool,
    pub required: bool,
}

/// Asset resolution result
#[derive(Debug)]
pub struct AssetResolutionResult {
    pub included_files: Vec<String>,
    pub template_files: Vec<String>,
    #[allow(dead_code)]
    pub total_size_bytes: u64,
}

/// Template variable definition
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TemplateVariable {
    pub description: String,
    pub default_value: Option<String>,
    pub required: bool,
    pub validation_pattern: Option<String>,
}

/// Available template variant information
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TemplateVariant {
    pub name: String,
    pub display_name: String,
    pub description: String,
    pub icon: Option<String>,
    pub complexity: String, // "simple", "medium", "advanced"
    pub use_cases: Vec<String>,
    pub requirements: TemplateRequirements,
    pub estimated_setup_time: String,
    pub assets: Option<TemplateAssets>,
}

/// Template asset configuration with inclusion/exclusion patterns
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TemplateAssets {
    pub includes: Vec<String>,
    pub excludes: Vec<String>,
    pub template_files: Vec<String>,
}

/// Result of template download operation
#[derive(Debug)]
pub struct TemplateDownloadResult {
    pub downloaded_files: Vec<String>,
    pub cached_files: Vec<String>,
    pub template_files_processed: Vec<String>,
    pub total_files: usize,
}

/// Remote asset fetcher
pub struct RemoteAssetFetcher {
    config: RemoteAssetSource,
    client: reqwest::Client,
}

impl RemoteAssetFetcher {
    pub fn new(config: RemoteAssetSource) -> Self {
        let client = reqwest::Client::builder()
            .user_agent("cargo-rustelo")
            .timeout(std::time::Duration::from_secs(30))
            .build()
            .unwrap();

        Self { config, client }
    }

    /// Discover available template variants from remote source
    pub async fn discover_templates(&self) -> Result<Vec<TemplateVariant>> {
        let url = format!("{}/templates.json", self.config.base_url);

        println!("🔍 Discovering available templates from: {}", url);

        match self.fetch_json::<Vec<TemplateVariant>>(&url).await {
            Ok(templates) => {
                println!("✅ Found {} template variants", templates.len());
                Ok(templates)
            }
            Err(e) => {
                if self.config.fallback_to_embedded {
                    println!(
                        "⚠️  Remote discovery failed, using embedded templates: {}",
                        e
                    );
                    Ok(self.get_embedded_templates())
                } else {
                    Err(e)
                }
            }
        }
    }

    /// Get template manifest for a specific variant
    #[allow(dead_code)]
    pub async fn get_template_manifest(&self, template_name: &str) -> Result<TemplateManifest> {
        let url = format!("{}/{}/manifest.json", self.config.base_url, template_name);

        println!("📋 Fetching manifest for template: {}", template_name);

        match self.fetch_json::<TemplateManifest>(&url).await {
            Ok(manifest) => Ok(manifest),
            Err(e) => {
                if self.config.fallback_to_embedded {
                    println!("⚠️  Remote manifest failed, using embedded fallback: {}", e);
                    Ok(self.get_embedded_manifest(template_name))
                } else {
                    Err(e)
                }
            }
        }
    }

    /// Check if template requirements are satisfied
    pub async fn check_requirements(
        &self,
        requirements: &TemplateRequirements,
    ) -> Result<RequirementCheckResult> {
        let mut result = RequirementCheckResult {
            satisfied: true,
            missing_requirements: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // Check Rust version
        if let Some(required_rust) = &requirements.rust_version {
            match self.check_rust_version(required_rust) {
                Ok(true) => {}
                Ok(false) => {
                    result.satisfied = false;
                    result
                        .missing_requirements
                        .push(format!("Rust version {} required", required_rust));
                }
                Err(e) => {
                    result
                        .warnings
                        .push(format!("Could not check Rust version: {}", e));
                }
            }
        }

        // Check Node.js version
        if let Some(required_node) = &requirements.node_version {
            match self.check_node_version(required_node) {
                Ok(true) => {}
                Ok(false) => {
                    result.satisfied = false;
                    result
                        .missing_requirements
                        .push(format!("Node.js version {} required", required_node));
                }
                Err(e) => {
                    result
                        .warnings
                        .push(format!("Could not check Node.js version: {}", e));
                }
            }
        }

        // Check system dependencies
        for dep in &requirements.system_dependencies {
            if !self.check_system_dependency(dep).await {
                result.satisfied = false;
                result
                    .missing_requirements
                    .push(format!("System dependency '{}' not found", dep));
            }
        }

        // Check optional dependencies and provide suggestions
        for dep in &requirements.optional_dependencies {
            if !self.check_system_dependency(dep).await {
                result.suggestions.push(format!(
                    "Consider installing '{}' for enhanced functionality",
                    dep
                ));
            }
        }

        // Check disk space
        if let Some(required_mb) = requirements.minimum_disk_space_mb {
            match self.check_disk_space(required_mb) {
                Ok(true) => {}
                Ok(false) => {
                    result.satisfied = false;
                    result
                        .missing_requirements
                        .push(format!("At least {}MB disk space required", required_mb));
                }
                Err(e) => {
                    result
                        .warnings
                        .push(format!("Could not check disk space: {}", e));
                }
            }
        }

        // Check platform support
        if !requirements.supported_platforms.is_empty() {
            let current_platform = self.get_current_platform();
            if !requirements.supported_platforms.contains(&current_platform) {
                result.warnings.push(format!(
                    "Platform '{}' not explicitly supported. Supported: {}",
                    current_platform,
                    requirements.supported_platforms.join(", ")
                ));
            }
        }

        Ok(result)
    }

    /// Download and cache template files
    #[allow(dead_code)]
    pub async fn download_template(
        &self,
        template_name: &str,
        target_path: &Path,
    ) -> Result<DownloadResult> {
        let manifest = self.get_template_manifest(template_name).await?;
        let mut result = DownloadResult {
            downloaded_files: Vec::new(),
            cached_files: Vec::new(),
            failed_files: Vec::new(),
            total_size_bytes: 0,
        };

        // Create target directory
        fs::create_dir_all(target_path).map_err(RusteloError::Io)?;

        // Create cache directory if caching enabled
        if self.config.cache_enabled {
            fs::create_dir_all(&self.config.cache_directory).map_err(RusteloError::Io)?;
        }

        // Download each file
        for file in &manifest.files {
            match self.download_file(file, template_name, target_path).await {
                Ok(file_result) => {
                    result.total_size_bytes += file_result.size_bytes;
                    if file_result.from_cache {
                        result.cached_files.push(file.path.clone());
                    } else {
                        result.downloaded_files.push(file.path.clone());
                    }

                    // Set executable permissions if needed
                    if file.is_executable {
                        let file_path = target_path.join(&file.path);
                        #[cfg(unix)]
                        {
                            use std::os::unix::fs::PermissionsExt;
                            let mut perms = fs::metadata(&file_path)
                                .map_err(RusteloError::Io)?
                                .permissions();
                            perms.set_mode(0o755);
                            fs::set_permissions(&file_path, perms).map_err(RusteloError::Io)?;
                        }
                    }
                }
                Err(e) => {
                    if file.required {
                        return Err(e);
                    } else {
                        result.failed_files.push(format!("{}: {}", file.path, e));
                    }
                }
            }
        }

        println!(
            "📦 Downloaded {} files, {} from cache ({}KB total)",
            result.downloaded_files.len(),
            result.cached_files.len(),
            result.total_size_bytes / 1024
        );

        Ok(result)
    }

    /// Download template using new asset inclusion system
    pub async fn download_template_with_assets(
        &self,
        template_variant: &TemplateVariant,
        target_path: &Path,
    ) -> Result<TemplateDownloadResult> {
        let mut result = TemplateDownloadResult {
            downloaded_files: Vec::new(),
            cached_files: Vec::new(),
            template_files_processed: Vec::new(),
            total_files: 0,
        };

        // Create target directory
        fs::create_dir_all(target_path).map_err(RusteloError::Io)?;

        // Get asset configuration
        let assets = match &template_variant.assets {
            Some(assets) => assets,
            None => return Err(RusteloError::generic("Template has no asset configuration")),
        };

        // Resolve asset patterns to actual file paths
        let resolved_assets = self.resolve_asset_patterns(assets).await?;

        println!(
            "📦 Resolved {} assets for template {}",
            resolved_assets.included_files.len(),
            template_variant.name
        );

        // Download regular asset files
        for asset_path in &resolved_assets.included_files {
            match self.download_asset_file(asset_path, target_path).await {
                Ok(from_cache) => {
                    result.total_files += 1;
                    if from_cache {
                        result.cached_files.push(asset_path.clone());
                    } else {
                        result.downloaded_files.push(asset_path.clone());
                    }
                }
                Err(e) => {
                    println!("⚠️  Failed to download {}: {}", asset_path, e);
                }
            }
        }

        // Download and process template files
        for template_file in &resolved_assets.template_files {
            match self
                .download_and_process_template_file(template_file, target_path, template_variant)
                .await
            {
                Ok(from_cache) => {
                    result.total_files += 1;
                    result.template_files_processed.push(template_file.clone());
                    if from_cache {
                        result.cached_files.push(template_file.clone());
                    } else {
                        result.downloaded_files.push(template_file.clone());
                    }
                }
                Err(e) => {
                    println!("⚠️  Failed to process template {}: {}", template_file, e);
                }
            }
        }

        println!(
            "✅ Downloaded {} files ({} from cache, {} templates processed)",
            result.total_files,
            result.cached_files.len(),
            result.template_files_processed.len()
        );

        Ok(result)
    }

    /// Resolve asset inclusion/exclusion patterns to actual file paths
    async fn resolve_asset_patterns(
        &self,
        assets: &TemplateAssets,
    ) -> Result<AssetResolutionResult> {
        let mut included_files = Vec::new();
        let mut template_files = Vec::new();

        // For each include pattern, resolve to actual files
        for pattern in &assets.includes {
            let resolved = self.resolve_pattern(pattern).await?;
            included_files.extend(resolved);
        }

        // Remove files that match exclude patterns
        for exclude_pattern in &assets.excludes {
            let excluded = self.resolve_pattern(exclude_pattern).await?;
            included_files.retain(|file| !excluded.contains(file));
        }

        // Add template files (these need special processing)
        template_files.extend(assets.template_files.clone());

        Ok(AssetResolutionResult {
            included_files,
            template_files,
            total_size_bytes: 0, // Will be calculated during download
        })
    }

    /// Resolve a single pattern (supports glob patterns)
    async fn resolve_pattern(&self, pattern: &str) -> Result<Vec<String>> {
        // For now, this is a simple implementation
        // In a full implementation, you'd query the remote server for available files
        // and match them against the pattern

        if pattern.contains('*') {
            // Handle glob patterns
            self.resolve_glob_pattern(pattern).await
        } else {
            // Direct file path
            Ok(vec![pattern.to_string()])
        }
    }

    /// Resolve glob patterns by querying remote file listings
    async fn resolve_glob_pattern(&self, pattern: &str) -> Result<Vec<String>> {
        println!("🔍 Resolving glob pattern: {}", pattern);

        // Handle local file:// URLs by actually walking the filesystem
        if self.config.base_url.starts_with("file://") {
            let source_base = self.config.base_url.strip_prefix("file://").unwrap();
            let base_path = PathBuf::from(source_base);

            // Use walkdir to find matching files
            use walkdir::WalkDir;

            let mut matches = Vec::new();

            // Convert glob pattern to a simple prefix match for now
            let pattern_parts: Vec<&str> = pattern.split('/').collect();
            let search_dir = base_path.join(pattern_parts[0]);

            if search_dir.exists() {
                for entry in WalkDir::new(search_dir).follow_links(false) {
                    match entry {
                        Ok(entry) => {
                            if entry.file_type().is_file() {
                                let relative_path = entry
                                    .path()
                                    .strip_prefix(&base_path)
                                    .unwrap_or(entry.path())
                                    .to_string_lossy()
                                    .replace('\\', "/");

                                // Simple pattern matching - could be improved with proper glob
                                if pattern.contains("**/*") {
                                    let prefix = pattern.replace("/**/*", "");
                                    if relative_path.starts_with(&prefix) {
                                        matches.push(relative_path);
                                    }
                                } else if relative_path.contains(&pattern.replace("/*", "")) {
                                    matches.push(relative_path);
                                }
                            }
                        }
                        Err(_) => continue,
                    }
                }
            }

            Ok(matches)
        } else {
            // For HTTP URLs, return empty for now (would need API support)
            Ok(Vec::new())
        }
    }

    /// Download a single asset file
    async fn download_asset_file(&self, asset_path: &str, target_path: &Path) -> Result<bool> {
        let local_path = target_path.join(asset_path.trim_start_matches("shared/"));

        // Create parent directories
        if let Some(parent) = local_path.parent() {
            fs::create_dir_all(parent).map_err(RusteloError::Io)?;
        }

        // Handle local file:// URLs
        if self.config.base_url.starts_with("file://") {
            let source_base = self.config.base_url.strip_prefix("file://").unwrap();
            let source_path = PathBuf::from(source_base).join(asset_path);

            if source_path.exists() {
                let content = fs::read(&source_path).map_err(RusteloError::Io)?;
                fs::write(&local_path, content).map_err(RusteloError::Io)?;
                return Ok(false); // not from cache, from local
            } else {
                return Err(RusteloError::generic(format!(
                    "Local file not found: {}",
                    source_path.display()
                )));
            }
        }

        // Check cache first for remote URLs
        if self.config.cache_enabled {
            let cache_file = self
                .config
                .cache_directory
                .join(asset_path.replace('/', "_"));
            if cache_file.exists() {
                let content = fs::read(&cache_file).map_err(RusteloError::Io)?;
                fs::write(&local_path, content).map_err(RusteloError::Io)?;
                return Ok(true); // from cache
            }
        }

        // Download from remote
        let url = format!("{}/{}", self.config.base_url, asset_path);
        let response = self
            .client
            .get(&url)
            .send()
            .await
            .map_err(|e| RusteloError::generic(format!("Failed to download {}: {}", url, e)))?;

        if !response.status().is_success() {
            return Err(RusteloError::generic(format!(
                "HTTP {}: {}",
                response.status(),
                url
            )));
        }

        let content = response
            .bytes()
            .await
            .map_err(|e| RusteloError::generic(format!("Failed to read response: {}", e)))?;

        fs::write(&local_path, &content).map_err(RusteloError::Io)?;

        // Cache if enabled
        if self.config.cache_enabled {
            let cache_file = self
                .config
                .cache_directory
                .join(asset_path.replace('/', "_"));
            if let Some(parent) = cache_file.parent() {
                let _ = fs::create_dir_all(parent);
            }
            let _ = fs::write(&cache_file, &content);
        }

        Ok(false) // not from cache
    }

    /// Download and process a template file (with variable substitution)
    async fn download_and_process_template_file(
        &self,
        template_path: &str,
        target_path: &Path,
        template_variant: &TemplateVariant,
    ) -> Result<bool> {
        let local_path = target_path.join(
            template_path
                .trim_start_matches("shared/")
                .trim_end_matches(".template"),
        );

        // Create parent directories
        if let Some(parent) = local_path.parent() {
            fs::create_dir_all(parent).map_err(RusteloError::Io)?;
        }

        // Get template content (handle local files)
        let template_content = if self.config.base_url.starts_with("file://") {
            // Handle local file
            let source_base = self.config.base_url.strip_prefix("file://").unwrap();
            let source_path = PathBuf::from(source_base).join(template_path);

            fs::read_to_string(&source_path).map_err(|e| {
                RusteloError::generic(format!(
                    "Failed to read local template {}: {}",
                    source_path.display(),
                    e
                ))
            })?
        } else {
            // Handle remote file
            let url = format!("{}/{}", self.config.base_url, template_path);
            let response = self.client.get(&url).send().await.map_err(|e| {
                RusteloError::generic(format!("Failed to download template {}: {}", url, e))
            })?;

            if !response.status().is_success() {
                return Err(RusteloError::generic(format!(
                    "HTTP {}: {}",
                    response.status(),
                    url
                )));
            }

            response
                .text()
                .await
                .map_err(|e| RusteloError::generic(format!("Failed to read template: {}", e)))?
        };

        // Process template variables (this would use a proper template engine in practice)
        let processed_content =
            self.process_template_variables(&template_content, template_variant);

        fs::write(&local_path, processed_content).map_err(RusteloError::Io)?;

        Ok(false) // Templates are always processed fresh
    }

    /// Process template variables in content
    fn process_template_variables(
        &self,
        content: &str,
        template_variant: &TemplateVariant,
    ) -> String {
        let mut result = content.to_string();

        // Basic template variable substitution
        result = result.replace("{{template_variant}}", &template_variant.name);
        result = result.replace("{{project_name}}", "placeholder-project");
        result = result.replace("{{rustelo_version}}", env!("CARGO_PKG_VERSION"));
        result = result.replace("{{generation_timestamp}}", &chrono::Utc::now().to_rfc3339());
        result = result.replace("{{asset_source}}", "remote");

        result
    }

    /// Download framework features dynamically
    #[allow(dead_code)]
    pub async fn discover_framework_features(&self) -> Result<FrameworkFeatures> {
        let url = format!("{}/framework-features.json", self.config.base_url);

        println!("🔍 Discovering framework features...");

        match self.fetch_json::<FrameworkFeatures>(&url).await {
            Ok(features) => {
                println!(
                    "✅ Discovered {} feature categories",
                    features.categories.len()
                );
                Ok(features)
            }
            Err(e) => {
                if self.config.fallback_to_embedded {
                    println!("⚠️  Remote feature discovery failed, using embedded: {}", e);
                    Ok(self.get_embedded_framework_features())
                } else {
                    Err(e)
                }
            }
        }
    }

    // Private helper methods...
    async fn fetch_json<T: for<'de> Deserialize<'de>>(&self, url: &str) -> Result<T> {
        // Handle local file:// URLs
        if url.starts_with("file://") {
            let path = url.strip_prefix("file://").unwrap();
            let content = fs::read_to_string(path)
                .map_err(|e| RusteloError::generic(format!("Failed to read local file: {}", e)))?;

            serde_json::from_str(&content)
                .map_err(|e| RusteloError::generic(format!("JSON parse error: {}", e)))
        } else {
            // Handle HTTP/HTTPS URLs
            let response = self
                .client
                .get(url)
                .send()
                .await
                .map_err(|e| RusteloError::generic(format!("HTTP request failed: {}", e)))?;

            if !response.status().is_success() {
                return Err(RusteloError::generic(format!(
                    "HTTP {}: {}",
                    response.status(),
                    url
                )));
            }

            let text = response
                .text()
                .await
                .map_err(|e| RusteloError::generic(format!("Failed to read response: {}", e)))?;

            serde_json::from_str(&text)
                .map_err(|e| RusteloError::generic(format!("JSON parse error: {}", e)))
        }
    }

    #[allow(dead_code)]
    async fn download_file(
        &self,
        file: &TemplateFile,
        template_name: &str,
        target_path: &Path,
    ) -> Result<FileDownloadResult> {
        let url = format!(
            "{}/{}/{}",
            self.config.base_url, template_name, file.source_path
        );
        let target_file = target_path.join(&file.path);

        // Check cache first
        if self.config.cache_enabled {
            let cache_file = self.config.cache_directory.join(format!(
                "{}_{}",
                template_name,
                file.source_path.replace('/', "_")
            ));

            if cache_file.exists() {
                if let Ok(metadata) = fs::metadata(&cache_file) {
                    let age = std::time::SystemTime::now()
                        .duration_since(
                            metadata
                                .modified()
                                .unwrap_or(std::time::SystemTime::UNIX_EPOCH),
                        )
                        .unwrap_or_default();

                    if age.as_secs() < (self.config.cache_ttl_hours * 3600) {
                        // Use cached version
                        if let Some(parent) = target_file.parent() {
                            fs::create_dir_all(parent).map_err(RusteloError::Io)?;
                        }
                        fs::copy(&cache_file, &target_file).map_err(RusteloError::Io)?;

                        return Ok(FileDownloadResult {
                            size_bytes: metadata.len(),
                            from_cache: true,
                        });
                    }
                }
            }
        }

        // Download from remote
        let response = self
            .client
            .get(&url)
            .send()
            .await
            .map_err(|e| RusteloError::generic(format!("Download failed: {}", e)))?;

        if !response.status().is_success() {
            return Err(RusteloError::generic(format!(
                "HTTP {}: {}",
                response.status(),
                url
            )));
        }

        let content = response
            .bytes()
            .await
            .map_err(|e| RusteloError::generic(format!("Failed to read file: {}", e)))?;

        let size_bytes = content.len() as u64;

        // Create parent directories
        if let Some(parent) = target_file.parent() {
            fs::create_dir_all(parent).map_err(RusteloError::Io)?;
        }

        // Write to target
        fs::write(&target_file, &content).map_err(RusteloError::Io)?;

        // Cache if enabled
        if self.config.cache_enabled {
            let cache_file = self.config.cache_directory.join(format!(
                "{}_{}",
                template_name,
                file.source_path.replace('/', "_")
            ));
            if let Some(parent) = cache_file.parent() {
                let _ = fs::create_dir_all(parent);
            }
            let _ = fs::write(&cache_file, &content);
        }

        Ok(FileDownloadResult {
            size_bytes,
            from_cache: false,
        })
    }

    // System requirement checking methods...
    fn check_rust_version(&self, _required: &str) -> Result<bool> {
        // Implementation for checking Rust version
        Ok(true) // Placeholder
    }

    fn check_node_version(&self, _required: &str) -> Result<bool> {
        // Implementation for checking Node.js version
        Ok(true) // Placeholder
    }

    async fn check_system_dependency(&self, _dep: &str) -> bool {
        // Implementation for checking system dependencies
        true // Placeholder
    }

    fn check_disk_space(&self, _required_mb: u64) -> Result<bool> {
        // Implementation for checking disk space
        Ok(true) // Placeholder
    }

    fn get_current_platform(&self) -> String {
        std::env::consts::OS.to_string()
    }

    // Embedded fallback methods...
    fn get_embedded_templates(&self) -> Vec<TemplateVariant> {
        vec![TemplateVariant {
            name: "basic".to_string(),
            display_name: "Basic".to_string(),
            description: "Standard web application template".to_string(),
            icon: Some("🏗️".to_string()),
            complexity: "simple".to_string(),
            use_cases: vec![
                "websites".to_string(),
                "blogs".to_string(),
                "portfolios".to_string(),
            ],
            requirements: TemplateRequirements {
                node_version: Some(">=18.0.0".to_string()),
                rust_version: Some(">=1.70.0".to_string()),
                system_dependencies: vec!["git".to_string()],
                optional_dependencies: vec!["docker".to_string()],
                framework_features: vec!["rustelo-web".to_string(), "rustelo-content".to_string()],
                minimum_disk_space_mb: Some(500),
                supported_platforms: vec![
                    "linux".to_string(),
                    "macos".to_string(),
                    "windows".to_string(),
                ],
            },
            estimated_setup_time: "5 minutes".to_string(),
            assets: Some(TemplateAssets {
                includes: vec![
                    "shared/scripts/setup/install.sh".to_string(),
                    "shared/configs/base/*.toml".to_string(),
                ],
                excludes: vec![],
                template_files: vec![
                    "shared/justfile.template".to_string(),
                    "shared/package.json.template".to_string(),
                    "shared/Cargo.toml.template".to_string(),
                ],
            }),
        }]
    }

    #[allow(dead_code)]
    fn get_embedded_manifest(&self, template_name: &str) -> TemplateManifest {
        // Return embedded template manifest
        TemplateManifest {
            name: template_name.to_string(),
            description: "Embedded template".to_string(),
            version: "embedded".to_string(),
            requirements: TemplateRequirements {
                node_version: Some(">=18.0.0".to_string()),
                rust_version: Some(">=1.70.0".to_string()),
                system_dependencies: vec![],
                optional_dependencies: vec![],
                framework_features: vec![],
                minimum_disk_space_mb: None,
                supported_platforms: vec![],
            },
            features: vec![],
            files: vec![],
            variables: HashMap::new(),
        }
    }

    #[allow(dead_code)]
    fn get_embedded_framework_features(&self) -> FrameworkFeatures {
        // Return embedded framework features
        FrameworkFeatures {
            version: env!("CARGO_PKG_VERSION").to_string(),
            categories: HashMap::new(),
        }
    }
}

// Result types
#[derive(Debug)]
pub struct RequirementCheckResult {
    pub satisfied: bool,
    pub missing_requirements: Vec<String>,
    pub warnings: Vec<String>,
    pub suggestions: Vec<String>,
}

#[derive(Debug)]
#[allow(dead_code)]
pub struct DownloadResult {
    pub downloaded_files: Vec<String>,
    pub cached_files: Vec<String>,
    pub failed_files: Vec<String>,
    pub total_size_bytes: u64,
}

#[derive(Debug)]
#[allow(dead_code)]
struct FileDownloadResult {
    pub size_bytes: u64,
    pub from_cache: bool,
}

/// Dynamic framework features structure
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct FrameworkFeatures {
    pub version: String,
    pub categories: HashMap<String, FeatureCategory>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct FeatureCategory {
    pub name: String,
    pub description: String,
    pub features: HashMap<String, Feature>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Feature {
    pub name: String,
    pub description: String,
    pub documentation_url: Option<String>,
    pub dependencies: Vec<String>,
    pub conflicts: Vec<String>,
    pub status: String, // "stable", "beta", "experimental"
    pub since_version: String,
}
