use std::fs;
use std::path::Path;
use std::sync::{Mutex, OnceLock};

use sgclaw::compat::config_adapter::{
    build_zeroclaw_config, build_zeroclaw_config_from_settings,
    build_zeroclaw_config_from_sgclaw_settings, resolve_skills_dir, zeroclaw_default_skills_dir,
    zeroclaw_workspace_dir,
};
use sgclaw::config::{
    BrowserBackend, DeepSeekSettings, OfficeBackend, PlannerMode, SgClawSettings, SkillsPromptMode,
};
use sgclaw::runtime::RuntimeProfile;
use uuid::Uuid;

fn env_lock() -> &'static Mutex<()> {
    static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
    LOCK.get_or_init(|| Mutex::new(()))
}

#[test]
fn zeroclaw_config_adapter_maps_deepseek_env_to_zeroclaw_config() {
    let _guard = env_lock().lock().unwrap();
    std::env::set_var("DEEPSEEK_API_KEY", "deepseek-test-key");
    std::env::set_var("DEEPSEEK_BASE_URL", "https://api.deepseek.com");
    std::env::set_var("DEEPSEEK_MODEL", "deepseek-chat");

    let config = build_zeroclaw_config(Path::new("/tmp/sgclaw")).unwrap();

    assert_eq!(config.default_provider.as_deref(), Some("deepseek"));
    assert_eq!(config.default_model.as_deref(), Some("deepseek-chat"));
    assert_eq!(config.api_key.as_deref(), Some("deepseek-test-key"));
    assert_eq!(config.api_url.as_deref(), Some("https://api.deepseek.com"));
    assert_eq!(
        config.workspace_dir,
        Path::new("/tmp/sgclaw/.sgclaw-zeroclaw-workspace")
    );
    assert_eq!(
        config.config_path,
        Path::new("/tmp/sgclaw/.sgclaw-zeroclaw-workspace/config.toml")
    );
}

#[test]
fn zeroclaw_config_adapter_uses_deterministic_workspace_dir() {
    let settings = DeepSeekSettings {
        api_key: "key".to_string(),
        base_url: "https://proxy.example.com/v1".to_string(),
        model: "deepseek-reasoner".to_string(),
        skills_dir: None,
    };

    let workspace_dir = zeroclaw_workspace_dir(Path::new("/var/lib/sgclaw"));
    let config = build_zeroclaw_config_from_settings(Path::new("/var/lib/sgclaw"), &settings);

    assert_eq!(
        workspace_dir,
        Path::new("/var/lib/sgclaw/.sgclaw-zeroclaw-workspace")
    );
    assert_eq!(config.workspace_dir, workspace_dir);
    assert_eq!(config.default_provider.as_deref(), Some("deepseek"));
    assert_eq!(config.default_model.as_deref(), Some("deepseek-reasoner"));
    assert_eq!(
        config.api_url.as_deref(),
        Some("https://proxy.example.com/v1")
    );
    assert_eq!(
        resolve_skills_dir(Path::new("/var/lib/sgclaw"), &settings),
        zeroclaw_default_skills_dir(Path::new("/var/lib/sgclaw"))
    );
}

#[test]
fn deepseek_settings_reload_from_browser_config_path_after_file_changes() {
    let root = std::env::temp_dir().join(format!("sgclaw-config-{}", Uuid::new_v4()));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-first",
  "baseUrl": "",
  "model": ""
}"#,
    )
    .unwrap();

    let first = DeepSeekSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected config file to produce settings");
    assert_eq!(first.api_key, "sk-first");
    assert_eq!(first.base_url, "https://api.deepseek.com");
    assert_eq!(first.model, "deepseek-chat");
    assert!(first.skills_dir.is_none());

    fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-second",
  "baseUrl": "https://proxy.example.com/v1",
  "model": "deepseek-reasoner",
  "skillsDir": "skill_lib"
}"#,
    )
    .unwrap();

    let second = DeepSeekSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected updated config file to produce settings");
    assert_eq!(second.api_key, "sk-second");
    assert_eq!(second.base_url, "https://proxy.example.com/v1");
    assert_eq!(second.model, "deepseek-reasoner");
    assert_eq!(second.skills_dir, Some(root.join("skill_lib")));
}

#[test]
fn ws_cleanup_resolves_single_configured_skills_dir() {
    let root = std::env::temp_dir().join(format!("sgclaw-skills-{}", Uuid::new_v4()));
    fs::create_dir_all(root.join("skill_lib/skills")).unwrap();
    let settings = DeepSeekSettings {
        api_key: "key".to_string(),
        base_url: "https://api.deepseek.com".to_string(),
        model: "deepseek-chat".to_string(),
        skills_dir: Some(root.join("skill_lib")),
    };

    let resolved = resolve_skills_dir(&root, &settings);

    assert_eq!(resolved, root.join("skill_lib/skills"));
}

#[test]
fn resolve_skills_dir_preserves_absolute_configured_skills_directory() {
    let root = std::env::temp_dir().join(format!("sgclaw-skills-{}", Uuid::new_v4()));
    let external_skills = root.join("external-skill-lib/skills");
    fs::create_dir_all(&external_skills).unwrap();
    let settings = DeepSeekSettings {
        api_key: "key".to_string(),
        base_url: "https://api.deepseek.com".to_string(),
        model: "deepseek-chat".to_string(),
        skills_dir: Some(external_skills.clone()),
    };

    let resolved = resolve_skills_dir(&root, &settings);

    assert_eq!(resolved, external_skills);
}

#[test]
fn sgclaw_settings_default_to_compact_skills_and_browser_attached_profile() {
    let settings = SgClawSettings::from_legacy_deepseek_fields(
        "sk-test".to_string(),
        "https://api.deepseek.com".to_string(),
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();

    assert_eq!(settings.runtime_profile, RuntimeProfile::BrowserAttached);
    assert_eq!(settings.skills_prompt_mode, SkillsPromptMode::Compact);
}

#[test]
fn sgclaw_settings_load_direct_submit_only_config_and_resolve_relative_skills_dir() {
    let root = std::env::temp_dir().join(format!("sgclaw-direct-submit-only-config-{}", Uuid::new_v4()));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "providers": [],
  "skillsDir": "skill_lib",
  "directSubmitSkill": "fault-details-report.collect_fault_details"
}"#,
    )
    .unwrap();

    let settings = SgClawSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected sgclaw settings from config file");

    assert_eq!(
        settings.direct_submit_skill.as_deref(),
        Some("fault-details-report.collect_fault_details")
    );
    assert_eq!(settings.skills_dir, Some(root.join("skill_lib")));
}

#[test]
fn sgclaw_settings_reject_invalid_direct_submit_skill_format() {
    let root = std::env::temp_dir().join(format!(
        "sgclaw-invalid-direct-submit-skill-{}",
        Uuid::new_v4()
    ));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "providers": [],
  "skillsDir": "skill_lib",
  "directSubmitSkill": "fault-details-report"
}"#,
    )
    .unwrap();

    let err = SgClawSettings::load(Some(config_path.as_path()))
        .expect_err("expected invalid directSubmitSkill format");
    let message = err.to_string();

    assert!(message.contains("directSubmitSkill"));
    assert!(message.contains("skill.tool"));
}

#[test]
fn sgclaw_settings_load_new_runtime_fields_from_browser_config() {
    let root = std::env::temp_dir().join(format!("sgclaw-runtime-config-{}", Uuid::new_v4()));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-runtime",
  "baseUrl": "https://api.deepseek.com",
  "model": "deepseek-chat",
  "skillsDir": "skill_lib",
  "runtimeProfile": "generalAssistant",
  "skillsPromptMode": "full"
}"#,
    )
    .unwrap();

    let settings = SgClawSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected sgclaw settings from config file");
    let config = build_zeroclaw_config_from_sgclaw_settings(&root, &settings);

    assert_eq!(settings.runtime_profile, RuntimeProfile::GeneralAssistant);
    assert_eq!(settings.skills_prompt_mode, SkillsPromptMode::Full);
    assert_eq!(settings.skills_dir, Some(root.join("skill_lib")));
    assert_eq!(config.skills.prompt_injection_mode, SkillsPromptMode::Full);
}

#[test]
fn ws_cleanup_rejects_array_style_skills_dir_config() {
    let root = std::env::temp_dir().join(format!("sgclaw-config-{}", uuid::Uuid::new_v4()));
    std::fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");
    std::fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-test",
  "baseUrl": "https://api.deepseek.com",
  "model": "deepseek-chat",
  "skillsDir": ["skill_lib", "skill_staging"]
}"#,
    )
    .unwrap();

    assert!(sgclaw::config::SgClawSettings::load(Some(config_path.as_path())).is_err());
}

#[test]
fn sgclaw_settings_load_browser_ws_url_from_browser_config() {
    let root = std::env::temp_dir().join(format!("sgclaw-browser-ws-config-{}", Uuid::new_v4()));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-runtime",
  "baseUrl": "https://api.deepseek.com",
  "model": "deepseek-chat",
  "browserWsUrl": "ws://127.0.0.1:12345"
}"#,
    )
    .unwrap();

    let settings = SgClawSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected sgclaw settings from config file");

    assert_eq!(
        settings.browser_ws_url.as_deref(),
        Some("ws://127.0.0.1:12345")
    );
}

#[test]
fn sgclaw_settings_load_service_ws_listen_addr_from_browser_config() {
    let root = std::env::temp_dir().join(format!("sgclaw-service-ws-config-{}", Uuid::new_v4()));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-runtime",
  "baseUrl": "https://api.deepseek.com",
  "model": "deepseek-chat",
  "serviceWsListenAddr": "127.0.0.1:42321"
}"#,
    )
    .unwrap();

    let settings = SgClawSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected sgclaw settings from config file");

    assert_eq!(
        settings.service_ws_listen_addr.as_deref(),
        Some("127.0.0.1:42321")
    );
}

#[test]
fn browser_attached_config_uses_low_temperature_for_deterministic_execution() {
    let settings = SgClawSettings::from_legacy_deepseek_fields(
        "sk-test".to_string(),
        "https://api.deepseek.com".to_string(),
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();

    let config = build_zeroclaw_config_from_sgclaw_settings(Path::new("/tmp/sgclaw"), &settings);

    assert_eq!(config.default_temperature, 0.0);
}

#[test]
fn sgclaw_settings_load_provider_switching_and_backend_policy_from_browser_config() {
    let root = std::env::temp_dir().join(format!("sgclaw-provider-config-{}", Uuid::new_v4()));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-legacy",
  "baseUrl": "https://api.deepseek.com",
  "model": "deepseek-chat",
  "plannerMode": "zeroclawPlanFirst",
  "activeProvider": "glm-prod",
  "browserBackend": "superrpa",
  "officeBackend": "openxml",
  "providers": [
    {
      "id": "deepseek-default",
      "provider": "deepseek",
      "apiKey": "sk-deepseek",
      "baseUrl": "https://api.deepseek.com",
      "model": "deepseek-chat"
    },
    {
      "id": "glm-prod",
      "provider": "glm",
      "apiKey": "sk-glm",
      "baseUrl": "https://open.bigmodel.cn/api/paas/v4",
      "model": "glm-4.5"
    }
  ]
}"#,
    )
    .unwrap();

    let settings = SgClawSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected sgclaw settings from config file");
    let config = build_zeroclaw_config_from_sgclaw_settings(&root, &settings);

    assert_eq!(settings.planner_mode, PlannerMode::ZeroclawPlanFirst);
    assert_eq!(settings.active_provider, "glm-prod");
    assert_eq!(settings.providers.len(), 2);
    assert_eq!(
        settings.provider_base_url,
        "https://open.bigmodel.cn/api/paas/v4"
    );
    assert_eq!(settings.provider_model, "glm-4.5");
    assert_eq!(settings.browser_backend, BrowserBackend::SuperRpa);
    assert_eq!(settings.office_backend, OfficeBackend::OpenXml);
    assert_eq!(config.default_provider.as_deref(), Some("glm"));
    assert_eq!(config.default_model.as_deref(), Some("glm-4.5"));
    assert_eq!(config.api_key.as_deref(), Some("sk-glm"));
    assert_eq!(
        config.api_url.as_deref(),
        Some("https://open.bigmodel.cn/api/paas/v4")
    );
    assert!(!config.browser.enabled);
    assert!(config.model_providers.contains_key("deepseek-default"));
    assert!(config.model_providers.contains_key("glm-prod"));
}

#[test]
fn sgclaw_settings_enable_non_host_browser_backend_when_requested() {
    let root = std::env::temp_dir().join(format!("sgclaw-browser-backend-{}", Uuid::new_v4()));
    fs::create_dir_all(&root).unwrap();
    let config_path = root.join("sgclaw_config.json");

    fs::write(
        &config_path,
        r#"{
  "apiKey": "sk-runtime",
  "baseUrl": "https://api.deepseek.com",
  "model": "deepseek-chat",
  "browserBackend": "rustNative"
}"#,
    )
    .unwrap();

    let settings = SgClawSettings::load(Some(config_path.as_path()))
        .unwrap()
        .expect("expected sgclaw settings from config file");
    let config = build_zeroclaw_config_from_sgclaw_settings(&root, &settings);

    assert_eq!(settings.browser_backend, BrowserBackend::RustNative);
    assert!(config.browser.enabled);
    assert_eq!(config.browser.backend, "rust_native");
}
