use std::collections::HashMap;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};

use zeroclaw::config::schema::ModelProviderConfig;
use zeroclaw::Config as ZeroClawConfig;

use crate::compat::cron_adapter::configure_embedded_cron;
use crate::compat::memory_adapter::configure_embedded_memory;
use crate::config::{BrowserBackend, DeepSeekSettings, SgClawSettings};
use crate::runtime::RuntimeProfile;

const SGCLAW_ZEROCLAW_WORKSPACE_DIR: &str = ".sgclaw-zeroclaw-workspace";
const SKILLS_DIR_NAME: &str = "skills";

pub fn build_zeroclaw_config(
    workspace_root: &Path,
) -> Result<ZeroClawConfig, crate::config::ConfigError> {
    let settings = SgClawSettings::from_env()?;
    Ok(build_zeroclaw_config_from_sgclaw_settings(
        workspace_root,
        &settings,
    ))
}

pub fn build_zeroclaw_config_from_settings(
    workspace_root: &Path,
    settings: &DeepSeekSettings,
) -> ZeroClawConfig {
    build_zeroclaw_config_from_sgclaw_settings(workspace_root, &SgClawSettings::from(settings))
}

pub fn build_zeroclaw_config_from_sgclaw_settings(
    workspace_root: &Path,
    settings: &SgClawSettings,
) -> ZeroClawConfig {
    let workspace_dir = zeroclaw_workspace_dir(workspace_root);
    let active_provider = settings.active_provider_settings();
    let mut config = ZeroClawConfig::default();
    config.workspace_dir = workspace_dir.clone();
    config.config_path = workspace_dir.join("config.toml");
    config.default_provider = Some(active_provider.provider.clone());
    config.default_model = Some(active_provider.model.clone());
    config.api_key = Some(active_provider.api_key.clone());
    config.api_url = active_provider.base_url.clone();
    config.api_path = active_provider.api_path.clone();
    config.default_temperature = match settings.runtime_profile {
        RuntimeProfile::BrowserAttached | RuntimeProfile::BrowserHeavy => 0.0,
        RuntimeProfile::GeneralAssistant => config.default_temperature,
    };
    config.skills.prompt_injection_mode = settings.skills_prompt_mode;
    config.model_providers = settings
        .providers
        .iter()
        .map(|provider| {
            (
                provider.id.clone(),
                ModelProviderConfig {
                    name: (!provider.provider.starts_with("custom:"))
                        .then(|| provider.provider.clone()),
                    base_url: provider.base_url.clone(),
                    api_path: provider.api_path.clone(),
                    wire_api: provider.wire_api.clone(),
                    requires_openai_auth: provider.requires_openai_auth,
                    azure_openai_resource: None,
                    azure_openai_deployment: None,
                    azure_openai_api_version: None,
                    max_tokens: None,
                },
            )
        })
        .collect::<HashMap<_, _>>();
    config.browser.enabled = !matches!(settings.browser_backend, BrowserBackend::SuperRpa);
    if let Some(backend) = settings.browser_backend.zeroclaw_backend() {
        config.browser.backend = backend.to_string();
    }
    configure_embedded_memory(&mut config);
    configure_embedded_cron(&mut config);
    config
}

pub fn zeroclaw_workspace_dir(workspace_root: &Path) -> PathBuf {
    workspace_root.join(SGCLAW_ZEROCLAW_WORKSPACE_DIR)
}

pub fn zeroclaw_default_skills_dir(workspace_root: &Path) -> PathBuf {
    zeroclaw_workspace_dir(workspace_root).join(SKILLS_DIR_NAME)
}

pub fn resolve_skills_dir(workspace_root: &Path, settings: &DeepSeekSettings) -> PathBuf {
    settings
        .skills_dir
        .as_deref()
        .map(normalize_configured_skills_dir)
        .unwrap_or_else(|| zeroclaw_default_skills_dir(workspace_root))
}

pub fn resolve_skills_dir_from_sgclaw_settings(
    workspace_root: &Path,
    settings: &SgClawSettings,
) -> PathBuf {
    settings
        .skills_dir
        .as_deref()
        .map(normalize_configured_skills_dir)
        .unwrap_or_else(|| zeroclaw_default_skills_dir(workspace_root))
}

fn normalize_configured_skills_dir(configured_dir: &Path) -> PathBuf {
    if configured_dir.file_name() == Some(OsStr::new(SKILLS_DIR_NAME)) {
        return configured_dir.to_path_buf();
    }

    let nested_skills_dir = configured_dir.join(SKILLS_DIR_NAME);
    if nested_skills_dir.is_dir() {
        nested_skills_dir
    } else {
        configured_dir.to_path_buf()
    }
}

