//! `BaseParams` 的模板上下文构建 —— 从 `base_parameters.rs` 拆出的 `to_template_context` 实体。
//!
//! 这里只负责把 `BaseParams` 的字段（含历史别名 `cargo_version`/`ProjectName`/
//! `default_host`/`default_port`/`go_version`）展开为模板渲染用的键值上下文。

use chrono::Datelike;
use serde_json::{Value, json};
use std::collections::HashMap;

use super::base_parameters::BaseParams;

/// 把 `BaseParams` 展开为模板上下文（键集与别名行为保持与历史逐字一致）。
pub fn build_base_context(params: &BaseParams) -> HashMap<String, Value> {
    let mut context = HashMap::new();

    // 项目基础信息
    context.insert("project_name".to_string(), json!(params.project_name));
    context.insert("project_version".to_string(), json!(params.project_version));
    context.insert("license".to_string(), json!(params.license));

    // 项目名称的不同格式
    context.insert(
        "project_name_pascal".to_string(),
        json!(crate::constants::string_utils::to_pascal_case(
            &params.project_name
        )),
    );
    context.insert(
        "project_name_snake".to_string(),
        json!(crate::constants::string_utils::to_snake_case(
            &params.project_name
        )),
    );

    // 为了兼容性添加别名
    context.insert("ProjectName".to_string(), json!(params.project_name));
    context.insert("cargo_version".to_string(), json!(params.project_version));

    // 项目描述
    if let Some(ref description) = params.project_description {
        context.insert("project_description".to_string(), json!(description));
        context.insert("cargo_description".to_string(), json!(description));
    } else {
        let default_description = format!(
            "A {} project generated by Scaffold-Gen",
            params.project_name
        );
        context.insert(
            "project_description".to_string(),
            json!(default_description),
        );
        context.insert("cargo_description".to_string(), json!(default_description));
    }

    // 作者信息
    if let Some(ref author) = params.author {
        context.insert("author".to_string(), json!(author));
    }

    // 当前年份
    let current_year = chrono::Utc::now().year();
    context.insert("year".to_string(), json!(current_year));

    // Git相关
    context.insert("enable_git".to_string(), json!(params.enable_git));
    context.insert(
        "enable_precommit".to_string(),
        json!(params.enable_precommit),
    );

    // 服务器配置
    if let Some(ref host) = params.host {
        context.insert("host".to_string(), json!(host));
        context.insert("default_host".to_string(), json!(host));
    }
    if let Some(port) = params.port {
        context.insert("port".to_string(), json!(port));
        context.insert("default_port".to_string(), json!(port));
    }

    // 通用功能开关
    context.insert("enable_swagger".to_string(), json!(params.enable_swagger));
    context.insert("enable_cors".to_string(), json!(params.enable_cors));
    context.insert("enable_logging".to_string(), json!(params.enable_logging));
    context.insert("enable_recovery".to_string(), json!(params.enable_recovery));
    context.insert(
        "enable_rate_limit".to_string(),
        json!(params.enable_rate_limit),
    );
    context.insert("enable_jwt".to_string(), json!(params.enable_jwt));
    context.insert("enable_database".to_string(), json!(params.enable_database));
    context.insert("enable_redis".to_string(), json!(params.enable_redis));

    // 数据库配置
    if let Some(ref db_type) = params.database_type {
        context.insert("database_type".to_string(), json!(db_type));
    }

    // 语言特定配置
    if let Some(ref version) = params.language_version {
        context.insert("go_version".to_string(), json!(version));
        context.insert("language_version".to_string(), json!(version));
    }
    if let Some(ref module) = params.module_name {
        context.insert("module_name".to_string(), json!(module));
    }
    context.insert("enable_modules".to_string(), json!(params.enable_modules));
    context.insert("enable_cgo".to_string(), json!(params.enable_cgo));
    context.insert("build_tags".to_string(), json!(params.build_tags));
    context.insert("enable_vendor".to_string(), json!(params.enable_vendor));

    context
}

#[cfg(test)]
mod tests {
    use super::super::parameters::Parameters;
    use super::*;

    fn keys_sorted(ctx: &HashMap<String, Value>) -> Vec<String> {
        let mut ks: Vec<String> = ctx.keys().cloned().collect();
        ks.sort();
        ks
    }

    #[test]
    fn to_template_context_contains_expected_key_set_for_defaults() {
        // Given: 默认 BaseParams（host/port 默认有值，description/author/db 默认无值）
        let params = BaseParams::new("my-app".to_string());

        // When
        let ctx = params.to_template_context();
        let keys = keys_sorted(&ctx);

        // Then: 锁定当前键集（含别名 cargo_version/ProjectName/default_host/default_port/go_version）
        let expected: Vec<&str> = vec![
            "ProjectName",
            "build_tags",
            "cargo_description",
            "cargo_version",
            "default_host",
            "default_port",
            "enable_cgo",
            "enable_cors",
            "enable_database",
            "enable_git",
            "enable_jwt",
            "enable_logging",
            "enable_modules",
            "enable_precommit",
            "enable_rate_limit",
            "enable_recovery",
            "enable_redis",
            "enable_swagger",
            "enable_vendor",
            "go_version",
            "host",
            "language_version",
            "license",
            "module_name",
            "port",
            "project_description",
            "project_name",
            "project_name_pascal",
            "project_name_snake",
            "project_version",
            "year",
        ];
        let expected: Vec<String> = expected.into_iter().map(String::from).collect();
        assert_eq!(keys, expected);
    }

    #[test]
    fn to_template_context_aliases_mirror_their_sources() {
        // Given
        let params = BaseParams::new("acme".to_string());

        // When
        let ctx = params.to_template_context();

        // Then: 别名值与源字段相等（锁定别名冗余的当前行为）
        assert_eq!(ctx["project_name"], ctx["ProjectName"]);
        assert_eq!(ctx["project_version"], ctx["cargo_version"]);
        assert_eq!(ctx["host"], ctx["default_host"]);
        assert_eq!(ctx["port"], ctx["default_port"]);
        assert_eq!(ctx["language_version"], ctx["go_version"]);
    }

    #[test]
    fn to_template_context_values_for_defaults() {
        // Given: 通过 BaseParams::new 构造（module_name 被设为 project_name）
        let params = BaseParams::new("my-app".to_string());

        // When
        let ctx = params.to_template_context();

        // Then: 锁定关键默认值
        assert_eq!(ctx["project_name"], serde_json::json!("my-app"));
        assert_eq!(ctx["project_version"], serde_json::json!("0.1.0"));
        assert_eq!(ctx["license"], serde_json::json!("MIT"));
        assert_eq!(ctx["module_name"], serde_json::json!("my-app"));
        assert_eq!(ctx["project_name_pascal"], serde_json::json!("MyApp"));
        assert_eq!(ctx["project_name_snake"], serde_json::json!("my-app"));
        assert_eq!(
            ctx["project_description"],
            serde_json::json!("A my-app project generated by Scaffold-Gen")
        );
        assert_eq!(ctx["cargo_description"], ctx["project_description"]);
        assert_eq!(ctx["host"], serde_json::json!("127.0.0.1"));
        assert_eq!(ctx["port"], serde_json::json!(8080));
        assert_eq!(ctx["language_version"], serde_json::json!("1.21"));
        assert_eq!(ctx["enable_git"], serde_json::json!(true));
        assert_eq!(ctx["enable_swagger"], serde_json::json!(true));
        assert_eq!(ctx["enable_database"], serde_json::json!(false));
    }

    #[test]
    fn to_template_context_omits_optional_keys_when_absent() {
        // Given: host/port/db/module/language_version 全部清空
        let params = BaseParams {
            host: None,
            port: None,
            database_type: None,
            module_name: None,
            language_version: None,
            project_description: None,
            author: None,
            ..BaseParams::new("bare".to_string())
        };

        // When
        let ctx = params.to_template_context();

        // Then: 条件键缺失，author 缺失，description 回退到默认描述
        assert!(!ctx.contains_key("host"));
        assert!(!ctx.contains_key("default_host"));
        assert!(!ctx.contains_key("port"));
        assert!(!ctx.contains_key("default_port"));
        assert!(!ctx.contains_key("database_type"));
        assert!(!ctx.contains_key("module_name"));
        assert!(!ctx.contains_key("go_version"));
        assert!(!ctx.contains_key("language_version"));
        assert!(!ctx.contains_key("author"));
        assert!(ctx.contains_key("project_description"));
    }

    #[test]
    fn to_template_context_includes_author_and_database_when_present() {
        // Given
        let params = BaseParams::new("svc".to_string())
            .with_author("alice".to_string())
            .with_database("postgres".to_string());

        // When
        let ctx = params.to_template_context();

        // Then
        assert_eq!(ctx["author"], serde_json::json!("alice"));
        assert_eq!(ctx["database_type"], serde_json::json!("postgres"));
        assert_eq!(ctx["enable_database"], serde_json::json!(true));
    }
}
