//! Collection functions for package service
//!
//! Functions for collecting binaries, configurations, and assets from the project.

use super::types::{AssetInfo, BinaryInfo, ConfigInfo, PackageConfig};
use super::utils;
use anyhow::Result;
use std::fs;
use std::path::Path;

/// Collect built binaries from target directory
pub(super) fn collect_binaries(project_root: &Path, config: &PackageConfig) -> Result<Vec<BinaryInfo>> {
    let target_dir = project_root
        .join("target")
        .join(config.target_arch.as_str())
        .join(&config.build_profile);

    if !target_dir.exists() {
        return Err(anyhow::anyhow!(
            "Target directory not found: {}. Did the build succeed?",
            target_dir.display()
        ));
    }

    let mut binaries = Vec::new();

    for entry in fs::read_dir(&target_dir)? {
        let entry = entry?;
        let path = entry.path();

        if path.is_file() && utils::is_executable(&path)? {
            if let Some(filename) = path.file_name() {
                let filename_str = filename.to_string_lossy();

                // Skip build artifacts
                if filename_str.starts_with('.') || filename_str.contains(".d") || filename_str.ends_with(".rlib") {
                    continue;
                }

                let metadata = path.metadata()?;
                let checksum = utils::calculate_checksum(&path)?;

                binaries.push(BinaryInfo {
                    name: filename_str.to_string(),
                    path: format!("bin/{}", filename_str),
                    size_bytes: metadata.len(),
                    checksum,
                });
            }
        }
    }

    if binaries.is_empty() {
        return Err(anyhow::anyhow!("No binaries found in target directory"));
    }

    Ok(binaries)
}

/// Collect configuration files from project
pub(super) fn collect_configs(project_root: &Path) -> Result<Vec<ConfigInfo>> {
    let mut configs = Vec::new();

    let config_dirs = vec![project_root.join("config"), project_root.join("configs")];

    for config_root in config_dirs {
        if config_root.exists() {
            collect_configs_recursive(&config_root, &config_root, &mut configs)?;
        }
    }

    Ok(configs)
}

/// Recursively collect config files
fn collect_configs_recursive(base_dir: &Path, current_dir: &Path, configs: &mut Vec<ConfigInfo>) -> Result<()> {
    for entry in fs::read_dir(current_dir)? {
        let entry = entry?;
        let path = entry.path();

        if path.is_dir() {
            collect_configs_recursive(base_dir, &path, configs)?;
        } else if path.is_file() {
            let extension = path.extension().and_then(|e| e.to_str());
            if matches!(extension, Some("json") | Some("yaml") | Some("yml") | Some("toml")) {
                let relative_path = path.strip_prefix(base_dir)?;
                let config_type = utils::determine_config_type(&path);
                let checksum = utils::calculate_checksum(&path)?;

                configs.push(ConfigInfo {
                    name: path.file_name().unwrap().to_string_lossy().to_string(),
                    path: format!("config/{}", relative_path.display()),
                    config_type,
                    checksum,
                });
            }
        }
    }

    Ok(())
}

/// Collect asset files from project
pub(super) fn collect_assets(project_root: &Path) -> Result<Vec<AssetInfo>> {
    let mut assets = Vec::new();

    let asset_dirs = vec![
        project_root.join("assets"),
        project_root.join("models"),
        project_root.join("data"),
        project_root.join("calibration"),
    ];

    for asset_root in asset_dirs {
        if asset_root.exists() {
            collect_assets_recursive(&asset_root, &asset_root, &mut assets)?;
        }
    }

    Ok(assets)
}

/// Recursively collect asset files
fn collect_assets_recursive(base_dir: &Path, current_dir: &Path, assets: &mut Vec<AssetInfo>) -> Result<()> {
    for entry in fs::read_dir(current_dir)? {
        let entry = entry?;
        let path = entry.path();

        if path.is_dir() {
            collect_assets_recursive(base_dir, &path, assets)?;
        } else if path.is_file() {
            let relative_path = path.strip_prefix(base_dir)?;
            let asset_type = utils::determine_asset_type(&path);
            let metadata = path.metadata()?;
            let checksum = utils::calculate_checksum(&path)?;

            assets.push(AssetInfo {
                name: path.file_name().unwrap().to_string_lossy().to_string(),
                path: format!("assets/{}", relative_path.display()),
                asset_type,
                size_bytes: metadata.len(),
                checksum,
            });
        }
    }

    Ok(())
}
