use folk_builder::codegen::{generate_cargo_toml, generate_lib_rs};
use folk_builder::config::{BuildConfig, BuildMeta, PluginEntry};

fn two_plugin_config() -> BuildConfig {
    BuildConfig {
        build: BuildMeta {
            output: "my-folk".into(),
            rust_version: "1.85".into(),
            folk_ext_path: None,
            folk_api_path: None,
        },
        plugin: vec![
            PluginEntry {
                crate_name: "folk_plugin_http".into(),
                version: Some("0.1".into()),
                path: None,
                git: None,
                config_key: "http".into(),
                features: Vec::new(),
            },
            PluginEntry {
                crate_name: "folk_plugin_jobs".into(),
                version: Some("0.1".into()),
                path: None,
                git: None,
                config_key: "jobs".into(),
                features: Vec::new(),
            },
        ],
    }
}

#[test]
fn codegen_main_contains_both_plugins() {
    let main_rs = generate_lib_rs(&two_plugin_config());
    assert!(main_rs.contains("folk_plugin_http_factory"));
    assert!(main_rs.contains("folk_plugin_jobs_factory"));
}

#[test]
fn codegen_main_contains_config_keys() {
    let main_rs = generate_lib_rs(&two_plugin_config());
    assert!(main_rs.contains(r#"raw_cfg.get("http")"#));
    assert!(main_rs.contains(r#"raw_cfg.get("jobs")"#));
}

#[test]
fn codegen_main_exposes_request_id_function() {
    let main_rs = generate_lib_rs(&two_plugin_config());
    assert!(main_rs.contains("pub fn folk_request_id() -> String"));
    assert!(main_rs.contains("wrap_function!(folk_request_id)"));
}

#[test]
fn codegen_main_exposes_request_body_read_functions() {
    // Phase 70: native body-streaming functions must be generated AND registered
    // (they come from the builder-generated module, not folk-ext's get_module).
    let main_rs = generate_lib_rs(&two_plugin_config());
    assert!(main_rs.contains("pub fn folk_read(length: i64) -> Binary<u8>"));
    assert!(main_rs.contains("pub fn folk_read_all() -> Binary<u8>"));
    assert!(main_rs.contains("wrap_function!(folk_read)"));
    assert!(main_rs.contains("wrap_function!(folk_read_all)"));
}

#[test]
fn codegen_main_exposes_multipart_functions() {
    // Phase 71: multipart streaming functions, generated + registered.
    let main_rs = generate_lib_rs(&two_plugin_config());
    assert!(main_rs.contains("pub fn folk_next_part() -> Option<String>"));
    assert!(main_rs.contains("pub fn folk_part_read(length: i64) -> Binary<u8>"));
    assert!(main_rs.contains("pub fn folk_part_read_all() -> Binary<u8>"));
    assert!(main_rs.contains("wrap_function!(folk_next_part)"));
    assert!(main_rs.contains("wrap_function!(folk_part_read)"));
    assert!(main_rs.contains("wrap_function!(folk_part_read_all)"));
}

#[test]
fn codegen_cargo_toml_contains_plugins() {
    let cargo = generate_cargo_toml(&two_plugin_config());
    assert!(cargo.contains(r#"folk_plugin_http = "0.1""#));
    assert!(cargo.contains(r#"folk_plugin_jobs = "0.1""#));
    assert!(cargo.contains(r#"name = "my-folk""#));
}

#[test]
fn codegen_cargo_toml_path_override() {
    let cfg = BuildConfig {
        build: BuildMeta {
            output: "test".into(),
            rust_version: "1.85".into(),
            folk_ext_path: None,
            folk_api_path: None,
        },
        plugin: vec![PluginEntry {
            crate_name: "my_plugin".into(),
            version: None,
            path: Some("../my-plugin".into()),
            git: None,
            config_key: String::new(),
            features: Vec::new(),
        }],
    };
    let cargo = generate_cargo_toml(&cfg);
    assert!(cargo.contains(r#"my_plugin = { path = "../my-plugin" }"#));
}

#[test]
fn codegen_cargo_toml_git_override() {
    let cfg = BuildConfig {
        build: BuildMeta {
            output: "test".into(),
            rust_version: "1.85".into(),
            folk_ext_path: None,
            folk_api_path: None,
        },
        plugin: vec![PluginEntry {
            crate_name: "my_plugin".into(),
            version: Some("0.2".into()),
            path: None,
            git: Some("https://github.com/example/plugin".into()),
            config_key: String::new(),
            features: Vec::new(),
        }],
    };
    let cargo = generate_cargo_toml(&cfg);
    assert!(
        cargo.contains(
            r#"my_plugin = { git = "https://github.com/example/plugin", version = "0.2" }"#
        )
    );
}

#[test]
fn codegen_cargo_toml_version_with_features() {
    let cfg = BuildConfig {
        build: BuildMeta {
            output: "test".into(),
            rust_version: "1.85".into(),
            folk_ext_path: None,
            folk_api_path: None,
        },
        plugin: vec![PluginEntry {
            crate_name: "folk_plugin_jobs".into(),
            version: Some("0.4".into()),
            path: None,
            git: None,
            config_key: "jobs".into(),
            features: vec!["redis".into(), "embedded".into()],
        }],
    };
    let cargo = generate_cargo_toml(&cfg);
    assert!(
        cargo.contains(
            r#"folk_plugin_jobs = { version = "0.4", features = ["redis", "embedded"] }"#
        ),
        "got: {cargo}"
    );
}

#[test]
fn codegen_cargo_toml_broker_features_passthrough() {
    // Phase 76: the broker driver features are plain strings forwarded verbatim
    // into the dependency line — no allowlist in the builder.
    let cfg = BuildConfig {
        build: BuildMeta {
            output: "test".into(),
            rust_version: "1.85".into(),
            folk_ext_path: None,
            folk_api_path: None,
        },
        plugin: vec![PluginEntry {
            crate_name: "folk_plugin_jobs".into(),
            version: Some("0.5".into()),
            path: None,
            git: None,
            config_key: "jobs".into(),
            features: vec!["rabbitmq".into(), "kafka".into()],
        }],
    };
    let cargo = generate_cargo_toml(&cfg);
    assert!(
        cargo.contains(
            r#"folk_plugin_jobs = { version = "0.5", features = ["rabbitmq", "kafka"] }"#
        ),
        "got: {cargo}"
    );
}

#[test]
fn codegen_cargo_toml_path_with_features() {
    let cfg = BuildConfig {
        build: BuildMeta {
            output: "test".into(),
            rust_version: "1.85".into(),
            folk_ext_path: None,
            folk_api_path: None,
        },
        plugin: vec![PluginEntry {
            crate_name: "folk_plugin_jobs".into(),
            version: None,
            path: Some("../folk-plugin-jobs".into()),
            git: None,
            config_key: "jobs".into(),
            features: vec!["embedded".into()],
        }],
    };
    let cargo = generate_cargo_toml(&cfg);
    assert!(
        cargo.contains(
            r#"folk_plugin_jobs = { path = "../folk-plugin-jobs", features = ["embedded"] }"#
        ),
        "got: {cargo}"
    );
}

#[test]
fn codegen_main_uses_crate_name_as_config_key_when_empty() {
    let cfg = BuildConfig {
        build: BuildMeta {
            output: "test".into(),
            rust_version: "1.85".into(),
            folk_ext_path: None,
            folk_api_path: None,
        },
        plugin: vec![PluginEntry {
            crate_name: "folk_plugin_http".into(),
            version: Some("0.1".into()),
            path: None,
            git: None,
            config_key: String::new(),
            features: Vec::new(),
        }],
    };
    let main_rs = generate_lib_rs(&cfg);
    assert!(main_rs.contains(r#"raw_cfg.get("folk_plugin_http")"#));
}
