use std::path::{Path, PathBuf};

use super::paths::{
    claude_mcp_json_path, cline_mcp_path, qoder_all_mcp_paths, qoderwork_mcp_path, roo_mcp_path,
    vscode_mcp_path, zed_config_dir, zed_settings_path,
};
use super::types::{ConfigType, EditorTarget};

pub fn build_targets(home: &Path) -> Vec<EditorTarget> {
    #[cfg(windows)]
    let opencode_cfg = if let Ok(appdata) = std::env::var("APPDATA") {
        PathBuf::from(appdata)
            .join("opencode")
            .join("opencode.json")
    } else {
        home.join(".config/opencode/opencode.json")
    };
    #[cfg(not(windows))]
    let opencode_cfg = home.join(".config/opencode/opencode.json");

    #[cfg(windows)]
    let opencode_detect = opencode_cfg
        .parent()
        .map(|p| p.to_path_buf())
        .unwrap_or_else(|| home.join(".config/opencode"));
    #[cfg(not(windows))]
    let opencode_detect = home.join(".config/opencode");

    let mut targets = vec![
        EditorTarget {
            name: "Cursor",
            agent_key: "cursor".to_string(),
            config_path: home.join(".cursor/mcp.json"),
            detect_path: home.join(".cursor"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Claude Code",
            agent_key: "claude".to_string(),
            config_path: claude_mcp_json_path(home),
            detect_path: detect_claude_path(),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Windsurf",
            agent_key: "windsurf".to_string(),
            config_path: home.join(".codeium/windsurf/mcp_config.json"),
            detect_path: home.join(".codeium/windsurf"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Codex CLI",
            agent_key: "codex".to_string(),
            config_path: crate::core::home::resolve_codex_dir()
                .unwrap_or_else(|| home.join(".codex"))
                .join("config.toml"),
            detect_path: detect_codex_path(home),
            config_type: ConfigType::Codex,
        },
        EditorTarget {
            name: "Gemini CLI",
            agent_key: "gemini".to_string(),
            config_path: home.join(".gemini/settings.json"),
            detect_path: home.join(".gemini"),
            config_type: ConfigType::GeminiSettings,
        },
        EditorTarget {
            name: "Antigravity",
            agent_key: "gemini".to_string(),
            config_path: home.join(".gemini/antigravity/mcp_config.json"),
            detect_path: home.join(".gemini/antigravity"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Zed",
            agent_key: "zed".to_string(),
            config_path: zed_settings_path(home),
            detect_path: zed_config_dir(home),
            config_type: ConfigType::Zed,
        },
        EditorTarget {
            name: "VS Code / Copilot",
            agent_key: "copilot".to_string(),
            config_path: vscode_mcp_path(),
            detect_path: detect_vscode_path(),
            config_type: ConfigType::VsCodeMcp,
        },
        EditorTarget {
            name: "OpenCode",
            agent_key: "opencode".to_string(),
            config_path: opencode_cfg,
            detect_path: opencode_detect,
            config_type: ConfigType::OpenCode,
        },
        EditorTarget {
            name: "Qwen Code",
            agent_key: "qwen".to_string(),
            config_path: home.join(".qwen/settings.json"),
            detect_path: home.join(".qwen"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Trae",
            agent_key: "trae".to_string(),
            config_path: home.join(".trae/mcp.json"),
            detect_path: home.join(".trae"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Amazon Q Developer",
            agent_key: "amazonq".to_string(),
            config_path: home.join(".aws/amazonq/default.json"),
            detect_path: home.join(".aws/amazonq"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "JetBrains IDEs",
            agent_key: "jetbrains".to_string(),
            config_path: home.join(".jb-mcp.json"),
            detect_path: detect_jetbrains_path(home),
            config_type: ConfigType::JetBrains,
        },
        EditorTarget {
            name: "Cline",
            agent_key: "cline".to_string(),
            config_path: cline_mcp_path(),
            detect_path: detect_cline_path(),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Roo Code",
            agent_key: "roo".to_string(),
            config_path: roo_mcp_path(),
            detect_path: detect_roo_path(),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "AWS Kiro",
            agent_key: "kiro".to_string(),
            config_path: home.join(".kiro/settings/mcp.json"),
            detect_path: home.join(".kiro"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Verdent",
            agent_key: "verdent".to_string(),
            config_path: home.join(".verdent/mcp.json"),
            detect_path: home.join(".verdent"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Crush",
            agent_key: "crush".to_string(),
            config_path: home.join(".config/crush/crush.json"),
            detect_path: home.join(".config/crush"),
            config_type: ConfigType::Crush,
        },
        EditorTarget {
            name: "Pi Coding Agent",
            agent_key: "pi".to_string(),
            config_path: home.join(".pi/agent/mcp.json"),
            detect_path: home.join(".pi/agent"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Amp",
            agent_key: "amp".to_string(),
            config_path: home.join(".config/amp/settings.json"),
            detect_path: home.join(".config/amp"),
            config_type: ConfigType::Amp,
        },
        EditorTarget {
            name: "QoderWork",
            agent_key: "qoderwork".to_string(),
            config_path: qoderwork_mcp_path(home),
            detect_path: detect_qoderwork_path(home),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Hermes Agent",
            agent_key: "hermes".to_string(),
            config_path: home.join(".hermes/config.yaml"),
            detect_path: home.join(".hermes"),
            config_type: ConfigType::HermesYaml,
        },
        EditorTarget {
            name: "Aider",
            agent_key: "aider".to_string(),
            config_path: home.join(".aider/mcp.json"),
            detect_path: home.join(".aider"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Continue",
            agent_key: "continue".to_string(),
            config_path: home.join(".continue/mcp.json"),
            detect_path: home.join(".continue"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Neovim (mcphub.nvim)",
            agent_key: "neovim".to_string(),
            config_path: home.join(".config/mcphub/servers.json"),
            detect_path: home.join(".config/nvim"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Emacs (mcp.el)",
            agent_key: "emacs".to_string(),
            config_path: home.join(".emacs.d/mcp.json"),
            detect_path: home.join(".emacs.d"),
            config_type: ConfigType::McpJson,
        },
        EditorTarget {
            name: "Sublime Text",
            agent_key: "sublime".to_string(),
            config_path: detect_sublime_mcp_path(home),
            detect_path: detect_sublime_path(home),
            config_type: ConfigType::McpJson,
        },
    ];

    targets.extend(
        qoder_all_mcp_paths(home)
            .into_iter()
            .map(|config_path| EditorTarget {
                name: "Qoder",
                agent_key: "qoder".to_string(),
                config_path,
                detect_path: detect_qoder_path(home),
                config_type: ConfigType::QoderSettings,
            }),
    );

    targets
}

fn detect_qoder_path(home: &Path) -> PathBuf {
    let qoder_dir = home.join(".qoder");
    if qoder_dir.exists() {
        return qoder_dir;
    }
    #[cfg(target_os = "macos")]
    {
        let app_dir = home.join("Library/Application Support/Qoder");
        if app_dir.exists() {
            return app_dir;
        }
    }
    #[cfg(target_os = "windows")]
    {
        if let Ok(appdata) = std::env::var("APPDATA") {
            let app_dir = PathBuf::from(appdata).join("Qoder");
            if app_dir.exists() {
                return app_dir;
            }
        }
    }
    PathBuf::from("/nonexistent")
}

fn detect_qoderwork_path(home: &Path) -> PathBuf {
    let dir = home.join(".qoderwork");
    if dir.exists() {
        return dir;
    }
    #[cfg(target_os = "windows")]
    {
        if let Ok(appdata) = std::env::var("APPDATA") {
            let app_dir = PathBuf::from(appdata).join("QoderWork");
            if app_dir.exists() {
                return app_dir;
            }
        }
    }
    PathBuf::from("/nonexistent")
}

fn detect_sublime_path(home: &Path) -> PathBuf {
    #[cfg(target_os = "macos")]
    {
        let app_dir = home.join("Library/Application Support/Sublime Text");
        if app_dir.exists() {
            return app_dir;
        }
    }
    let xdg_dir = home.join(".config/sublime-text");
    if xdg_dir.exists() {
        return xdg_dir;
    }
    #[cfg(target_os = "windows")]
    {
        if let Ok(appdata) = std::env::var("APPDATA") {
            let app_dir = PathBuf::from(appdata).join("Sublime Text");
            if app_dir.exists() {
                return app_dir;
            }
        }
    }
    PathBuf::from("/nonexistent")
}

fn detect_sublime_mcp_path(home: &Path) -> PathBuf {
    #[cfg(target_os = "macos")]
    {
        let app_dir = home.join("Library/Application Support/Sublime Text/Packages/User/mcp.json");
        if app_dir.parent().is_some_and(std::path::Path::exists) {
            return app_dir;
        }
    }
    home.join(".config/sublime-text/mcp.json")
}

pub fn detect_claude_path() -> PathBuf {
    let which_cmd = if cfg!(windows) { "where" } else { "which" };
    if let Ok(output) = std::process::Command::new(which_cmd).arg("claude").output() {
        if output.status.success() {
            return PathBuf::from(String::from_utf8_lossy(&output.stdout).trim());
        }
    }
    if let Ok(dir) = std::env::var("CLAUDE_CONFIG_DIR") {
        let dir = dir.trim();
        if !dir.is_empty() {
            let p = PathBuf::from(dir);
            if p.exists() {
                return p;
            }
        }
    }
    if let Some(home) = dirs::home_dir() {
        let claude_json = claude_mcp_json_path(&home);
        if claude_json.exists() {
            return claude_json;
        }
    }
    PathBuf::from("/nonexistent")
}

pub fn detect_codex_path(home: &Path) -> PathBuf {
    let codex_dir = crate::core::home::resolve_codex_dir().unwrap_or_else(|| home.join(".codex"));
    if codex_dir.exists() {
        return codex_dir;
    }
    let which_cmd = if cfg!(windows) { "where" } else { "which" };
    if let Ok(output) = std::process::Command::new(which_cmd).arg("codex").output() {
        if output.status.success() {
            return codex_dir;
        }
    }
    PathBuf::from("/nonexistent")
}

pub fn detect_vscode_path() -> PathBuf {
    #[cfg(target_os = "macos")]
    {
        if let Some(home) = dirs::home_dir() {
            let vscode = home.join("Library/Application Support/Code/User/settings.json");
            if vscode.exists() {
                return vscode;
            }
        }
    }
    #[cfg(target_os = "linux")]
    {
        if let Some(home) = dirs::home_dir() {
            let vscode = home.join(".config/Code/User/settings.json");
            if vscode.exists() {
                return vscode;
            }
        }
    }
    #[cfg(target_os = "windows")]
    {
        if let Ok(appdata) = std::env::var("APPDATA") {
            let vscode = PathBuf::from(appdata).join("Code/User/settings.json");
            if vscode.exists() {
                return vscode;
            }
        }
    }
    let which_cmd = if cfg!(windows) { "where" } else { "which" };
    if let Ok(output) = std::process::Command::new(which_cmd).arg("code").output() {
        if output.status.success() {
            return PathBuf::from(String::from_utf8_lossy(&output.stdout).trim());
        }
    }
    PathBuf::from("/nonexistent")
}

pub fn detect_jetbrains_path(home: &Path) -> PathBuf {
    #[cfg(target_os = "macos")]
    {
        let lib = home.join("Library/Application Support/JetBrains");
        if lib.exists() {
            return lib;
        }
    }
    #[cfg(target_os = "linux")]
    {
        let cfg = home.join(".config/JetBrains");
        if cfg.exists() {
            return cfg;
        }
    }
    #[cfg(target_os = "windows")]
    {
        if let Ok(appdata) = std::env::var("APPDATA") {
            let jb = std::path::PathBuf::from(appdata).join("JetBrains");
            if jb.exists() {
                return jb;
            }
        }
        if let Ok(local) = std::env::var("LOCALAPPDATA") {
            let jb = std::path::PathBuf::from(local).join("JetBrains");
            if jb.exists() {
                return jb;
            }
        }
    }
    if home.join(".jb-mcp.json").exists() {
        return home.join(".jb-mcp.json");
    }
    PathBuf::from("/nonexistent")
}

#[allow(unreachable_code)]
pub fn detect_cline_path() -> PathBuf {
    #[cfg(target_os = "windows")]
    {
        if let Ok(appdata) = std::env::var("APPDATA") {
            let p = PathBuf::from(appdata).join("Code/User/globalStorage/saoudrizwan.claude-dev");
            if p.exists() {
                return p;
            }
        }
        return PathBuf::from("/nonexistent");
    }

    let Some(home) = dirs::home_dir() else {
        return PathBuf::from("/nonexistent");
    };
    #[cfg(target_os = "macos")]
    {
        let p =
            home.join("Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev");
        if p.exists() {
            return p;
        }
    }
    #[cfg(target_os = "linux")]
    {
        let p = home.join(".config/Code/User/globalStorage/saoudrizwan.claude-dev");
        if p.exists() {
            return p;
        }
    }
    PathBuf::from("/nonexistent")
}

#[allow(unreachable_code)]
pub fn detect_roo_path() -> PathBuf {
    #[cfg(target_os = "windows")]
    {
        if let Ok(appdata) = std::env::var("APPDATA") {
            let p =
                PathBuf::from(appdata).join("Code/User/globalStorage/rooveterinaryinc.roo-cline");
            if p.exists() {
                return p;
            }
        }
        return PathBuf::from("/nonexistent");
    }

    let Some(home) = dirs::home_dir() else {
        return PathBuf::from("/nonexistent");
    };
    #[cfg(target_os = "macos")]
    {
        let p = home
            .join("Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline");
        if p.exists() {
            return p;
        }
    }
    #[cfg(target_os = "linux")]
    {
        let p = home.join(".config/Code/User/globalStorage/rooveterinaryinc.roo-cline");
        if p.exists() {
            return p;
        }
    }
    PathBuf::from("/nonexistent")
}

#[cfg(all(test, target_os = "macos"))]
mod tests {
    use super::*;

    #[test]
    #[cfg(target_os = "macos")]
    fn build_targets_includes_all_qoder_macos_mcp_locations() {
        let home = Path::new("/Users/tester");
        let qoder_paths: Vec<_> = build_targets(home)
            .into_iter()
            .filter(|target| target.agent_key == "qoder")
            .map(|target| target.config_path)
            .collect();

        assert_eq!(
            qoder_paths,
            vec![
                home.join(".qoder/mcp.json"),
                home.join("Library/Application Support/Qoder/User/mcp.json"),
                home.join("Library/Application Support/Qoder/SharedClientCache/mcp.json"),
            ]
        );
    }
}
