use colored::Colorize;
use std::path::Path;

use crate::errors::KamError;
use crate::types::kam_toml::KamToml;
use crate::utils::Utils;

use super::args::ValidateArgs;

struct ValidationMessages {
    errors: Vec<String>,
    warnings: Vec<String>,
}

/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public function 'run'. Replace with real documentation. (2025-12-30T22:23:21Z)
///
/// # Errors
/// Returns `KamError` if kam.toml cannot be loaded or parsed (I/O errors, parsing errors).
pub fn run(args: &ValidateArgs) -> Result<(), KamError> {
    let project_path = Path::new(&args.path);
    let kam_toml_path = project_path.join("kam.toml");

    if !kam_toml_path.exists() {
        Utils::error(&trf!("kam.toml.not_found_at", &kam_toml_path.display()));
        return Ok(());
    }

    Utils::info(&trf!("validate.validating", &kam_toml_path.display()));

    let kam_toml = match KamToml::load_from_file(&kam_toml_path) {
        Ok(kt) => kt,
        Err(e) => {
            Utils::error(&trf!("kam.toml.failed_to_parse", &e));
            return Ok(());
        }
    };

    let messages = validate_kam_toml(project_path, &kam_toml);
    print_validation_result(&messages);

    Ok(())
}

fn validate_kam_toml(project_path: &Path, kam_toml: &KamToml) -> ValidationMessages {
    let mut messages = ValidationMessages {
        errors: Vec::new(),
        warnings: Vec::new(),
    };

    validate_prop_section(kam_toml, &mut messages);
    validate_mmrl_repo_section(project_path, kam_toml, &mut messages);
    validate_build_section(project_path, kam_toml, &mut messages);

    messages
}

fn validate_prop_section(kam_toml: &KamToml, messages: &mut ValidationMessages) {
    if kam_toml.prop.id.trim().is_empty() {
        messages
            .errors
            .push(crate::i18n::tr("validate.prop.id_required"));
    } else if !kam_toml
        .prop
        .id
        .chars()
        .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
    {
        // id只能包含字母数字、下划线、横线、点号
        messages
            .errors
            .push(crate::i18n::tr("validate.prop.id_invalid_characters"));
    }

    if kam_toml.prop.name.trim().is_empty() {
        messages
            .errors
            .push(crate::i18n::tr("validate.prop.name_required"));
    }

    if kam_toml.prop.version.trim().is_empty() {
        messages
            .errors
            .push(crate::i18n::tr("validate.prop.version_required"));
    }

    if kam_toml.prop.versionCode <= 0 {
        messages.errors.push(crate::i18n::tr(
            "validate.prop.version_code_should_be_positive",
        ));
    }

    if kam_toml.prop.description.trim().is_empty() {
        messages
            .errors
            .push(crate::i18n::tr("validate.prop.description_required"));
    }

    // author是可选的，但建议填写（所以是warning不是error）
    if kam_toml
        .prop
        .author
        .as_ref()
        .is_none_or(|a| a.trim().is_empty())
    {
        messages
            .warnings
            .push(crate::i18n::tr("validate.prop.author_empty_recommended"));
    }
}

fn validate_mmrl_repo_section(
    project_path: &Path,
    kam_toml: &KamToml,
    messages: &mut ValidationMessages,
) {
    if let Some(mmrl) = &kam_toml.mmrl
        && let Some(repo) = &mmrl.repo
    {
        // 检查推荐字段（license建议填写）
        if repo.license.as_deref().unwrap_or("").is_empty() {
            messages
                .warnings
                .push(crate::i18n::tr("validate.mmrl.repo.license_recommended"));
        }

        // 检查文件是否存在（如果配置了但文件不存在就是错误）
        check_file_exists(
            project_path,
            repo.license_file.as_ref(),
            crate::i18n::tr("validate.mmrl.repo.license_file"),
            &mut messages.errors,
        );
        check_file_exists(
            project_path,
            repo.readme_file.as_ref(),
            crate::i18n::tr("validate.mmrl.repo.readme_file"),
            &mut messages.errors,
        );
        check_file_exists(
            project_path,
            repo.changelog_file.as_ref(),
            crate::i18n::tr("validate.mmrl.repo.changelog_file"),
            &mut messages.errors,
        );
    }
}

fn validate_build_section(
    project_path: &Path,
    kam_toml: &KamToml,
    messages: &mut ValidationMessages,
) {
    if let Some(build) = &kam_toml.kam.build {
        // 检查源码目录（自定义的或默认的）
        let src_dir = if let Some(custom) = &build.source_dir {
            project_path.join(custom)
        } else {
            project_path.join("src").join(&kam_toml.prop.id) // 默认是 src/<id>
        };

        if !src_dir.exists() {
            // 源码目录不存在只是警告，因为可能还没创建
            messages.warnings.push(trf!(
                "validate.source_dir_missing_might_fail",
                &src_dir.display()
            ));
        }

        // 检查hooks目录
        if let Some(hooks) = &build.hooks_dir {
            let hooks_path = project_path.join(hooks);
            // 只有用户明确设置了非默认路径但不存在时才警告
            // 默认的"hooks"目录不存在不算问题（可能不需要hooks）
            if !hooks_path.exists() && hooks != "hooks" {
                messages.warnings.push(trf!(
                    "Hooks directory '{}' specified but does not exist",
                    hooks
                ));
            }
        }
    } else {
        // 没有build配置，检查默认源码目录
        let default_src = project_path.join("src").join(&kam_toml.prop.id);
        if !default_src.exists() {
            messages.warnings.push(trf!(
                "validate.default_source_dir_not_found",
                &default_src.display()
            ));
        }
    }
}

fn print_validation_result(messages: &ValidationMessages) {
    println!();
    if messages.errors.is_empty() && messages.warnings.is_empty() {
        Utils::success(crate::i18n::tr("validate.no_issues_kam_toml_valid"));
        return;
    }

    print_errors(&messages.errors);
    print_warnings(&messages.errors, &messages.warnings);

    println!();
    if messages.errors.is_empty() {
        Utils::warn(crate::i18n::tr("validate.passed_with_warnings"));
    } else {
        Utils::error(crate::i18n::tr("validate.failed"));
    }
}

fn print_errors(errors: &[String]) {
    if errors.is_empty() {
        return;
    }

    let color = Utils::error_color();
    println!(
        "{}",
        crate::i18n::tr("validate.errors.header")
            .color(color)
            .bold()
    );
    for error in errors {
        println!("  {} {}", "✗".color(color).bold(), error.color(color));
    }
}

fn print_warnings(errors: &[String], warnings: &[String]) {
    if warnings.is_empty() {
        return;
    }

    if !errors.is_empty() {
        println!();
    }
    println!(
        "{}",
        crate::i18n::tr("validate.warnings.header").yellow().bold()
    );
    for warning in warnings {
        println!("  {} {}", "!".yellow().bold(), warning.yellow());
    }
}

// 检查文件是否存在
// 如果配置了文件路径但文件不存在，就加到错误列表里
fn check_file_exists<P: AsRef<str>>(
    base: &Path,
    file: Option<&String>,
    name: P,
    errors: &mut Vec<String>,
) {
    if let Some(f) = file
        && !f.is_empty()
        && !base.join(f).exists()
    {
        errors.push(trf!("{} '{}' not found", name.as_ref(), f));
    }
}
