use crate::errors::KamError;
use crate::template::TemplateCacheManager;
use crate::utils::Utils;
use std::collections::HashMap;
use std::fs;
use std::path::Path;
use zip::ZipArchive;

// 从.tar.gz文件导入单个模板
// 如果指定了name就用指定的，否则从文件名提取
/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public function 'import_single_template'. Replace with real documentation. (2025-12-30T22:23:21Z)
///
/// # Errors
/// Returns `KamError` if the archive file is not found, cannot be copied, or template already exists (unless `force` is true).
pub fn import_single_template(
    archive_path: &Path,
    name: Option<String>,
    force: bool,
) -> Result<(), KamError> {
    if !archive_path.exists() {
        return Err(KamError::InvalidDirectory(format!(
            "Archive file not found: {}",
            archive_path.display()
        )));
    }

    // 确定模板名字
    // 如果用户指定了就用指定的，否则从文件名提取
    let template_name = if let Some(n) = name {
        n
    } else {
        // 从文件名提取（去掉扩展名）
        let filename = archive_path
            .file_stem()
            .and_then(|s| s.to_str())
            .ok_or_else(|| {
                KamError::InvalidDirectory("Could not determine template name".to_string())
            })?;

        // 处理.tar.gz的情况，file_stem会返回"template.tar"
        // 需要再去掉.tar后缀
        let clean_name = Path::new(filename)
            .file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or(filename);

        clean_name.to_string()
    };

    let cache_dir = TemplateCacheManager::get_cache_dir()?;
    let dest_path = cache_dir.join(format!("{template_name}.tar.gz"));

    // 检查模板是否已存在
    if dest_path.exists() && !force {
        return Err(KamError::CommandFailed(format!(
            "Template '{template_name}' already exists. Use --force to overwrite."
        )));
    }

    // 直接复制到缓存目录（简单粗暴）
    fs::copy(archive_path, &dest_path).map_err(KamError::Io)?;

    Utils::success(format!("Template '{template_name}' imported successfully"));

    Ok(())
}

// 从.zip文件导入多个模板
// ZIP里可能包含多个.tar.gz文件，也可能包含目录结构的模板
/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public function 'import_multiple_templates'. Replace with real documentation. (2025-12-30T22:23:21Z)
///
/// # Errors
/// Returns `KamError` if the ZIP file cannot be opened, read, or extracted (I/O errors, ZIP parsing errors).
#[allow(clippy::too_many_lines)]
pub fn import_multiple_templates(zip_path: &Path, force: bool) -> Result<(), KamError> {
    if !zip_path.exists() {
        return Err(KamError::InvalidDirectory(format!(
            "ZIP file not found: {}",
            zip_path.display()
        )));
    }

    let file = fs::File::open(zip_path).map_err(KamError::Io)?;
    let mut archive = ZipArchive::new(file)
        .map_err(|e| KamError::CommandFailed(format!("Failed to open ZIP archive: {e}")))?;

    let cache_dir = TemplateCacheManager::get_cache_dir()?;
    let mut imported_count = 0;
    let mut skipped_count = 0;

    // 提取.tar.gz文件，也处理ZIP里的目录结构模板
    // 先收集顶层目录的条目，后面再提取到模板缓存
    let mut dir_groups: HashMap<String, Vec<usize>> = HashMap::new();

    for i in 0..archive.len() {
        let mut file = archive
            .by_index(i)
            .map_err(|e| KamError::CommandFailed(format!("Failed to read ZIP entry: {e}")))?;

        let outpath = match file.enclosed_name() {
            Some(path) => path.clone(),
            None => continue,
        };

        let outpath_str = outpath.to_string_lossy();

        // 如果是.tar.gz文件，当作单个模板压缩包处理
        if outpath_str.ends_with(".tar.gz") {
            let filename = outpath
                .file_name()
                .and_then(|s| s.to_str())
                .ok_or_else(|| KamError::InvalidDirectory("Invalid filename in ZIP".to_string()))?;

            let dest_path = cache_dir.join(filename);

            // Check if exists
            if dest_path.exists() && !force {
                Utils::warn(format!(
                    "Template '{}' already exists, skipping",
                    filename.strip_suffix(".tar.gz").unwrap_or(filename)
                ));
                skipped_count += 1;
                continue;
            }

            // Extract to cache directory
            let mut outfile = fs::File::create(&dest_path).map_err(KamError::Io)?;
            std::io::copy(&mut file, &mut outfile).map_err(KamError::Io)?;

            Utils::success(format!(
                "Template '{}' imported",
                filename.strip_suffix(".tar.gz").unwrap_or(filename)
            ));
            imported_count += 1;
        } else {
            // Non .tar.gz entry - consider grouping by top-level directory name
            if let Some(component) = outpath.components().next()
                && let std::path::Component::Normal(os_str) = component
                && let Some(top) = os_str.to_str()
            {
                dir_groups.entry(top.to_string()).or_default().push(i);
            }
        }
    }

    // Process grouped directory entries as templates
    for (top, indices) in dir_groups {
        let dest_dir = cache_dir.join(&top);

        // If template exists in cache and force is not set, skip
        if dest_dir.exists() && !force {
            Utils::warn(format!("Template '{top}' already exists, skipping"));
            skipped_count += 1;
            continue;
        }

        // Extract grouped entries into a temporary directory and then copy into cache
        let temp_dir = tempfile::tempdir().map_err(KamError::Io)?;
        for idx in indices {
            let mut file = archive
                .by_index(idx)
                .map_err(|e| KamError::CommandFailed(format!("Failed to read ZIP entry: {e}")))?;

            let entry_path = match file.enclosed_name() {
                Some(p) => p.clone(),
                None => continue,
            };

            // Compute relative subpath under the top directory
            let subpath = entry_path
                .strip_prefix(&top)
                .map_or_else(|_| entry_path.clone(), std::borrow::ToOwned::to_owned);

            let out_target = temp_dir.path().join(&subpath);

            if file.is_dir() {
                fs::create_dir_all(&out_target).map_err(KamError::Io)?;
            } else {
                if let Some(parent) = out_target.parent() {
                    fs::create_dir_all(parent).map_err(KamError::Io)?;
                }
                let mut outfile = fs::File::create(&out_target).map_err(KamError::Io)?;
                std::io::copy(&mut file, &mut outfile).map_err(KamError::Io)?;
            }
        }

        // Install into cache: remove existing (if any), then copy from temp
        if dest_dir.exists() {
            fs::remove_dir_all(&dest_dir).map_err(KamError::Io)?;
        }
        crate::utils::copy_dir_all(temp_dir.path(), &dest_dir).map_err(KamError::Io)?;

        Utils::success(format!("Template '{top}' imported"));
        imported_count += 1;
    }
    if imported_count > 0 {
        println!();
        Utils::success(format!(
            "Successfully imported {imported_count} template(s)"
        ));
    }

    if skipped_count > 0 {
        Utils::warn(format!(
            "Skipped {skipped_count} template(s) (already exist)"
        ));
    }

    if imported_count == 0 && skipped_count == 0 {
        Utils::warn("No .tar.gz templates found in ZIP file");
    }

    Ok(())
}

// 主导入函数，检测文件类型然后调用相应的处理函数
// 支持.tar.gz和.zip两种格式
/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public function 'import_template'. Replace with real documentation. (2025-12-30T22:23:21Z)
///
/// # Errors
/// Returns `KamError` if the file format is unsupported or import operations fail.
pub fn import_template(path: &Path, name: Option<String>, force: bool) -> Result<(), KamError> {
    let extension = path.extension().and_then(|s| s.to_str()).unwrap_or("");

    let path_str = path.to_string_lossy();

    if path_str.ends_with(".tar.gz") || extension == "tgz" {
        // Single template import
        import_single_template(path, name, force)
    } else if extension == "zip" {
        // Multiple templates import
        if name.is_some() {
            Utils::warn(
                "Note: --name is ignored when importing from ZIP (contains multiple templates)",
            );
        }
        import_multiple_templates(path, force)
    } else {
        Err(KamError::CommandFailed("Unsupported file format. Use .tar.gz for single template or .zip for multiple templates".to_string()))
    }
}
