use crate::commands::servers::list_servers;
use crate::db::pool;
use rusqlite::params;
use std::path::PathBuf;
use std::process::Command;
use serde::{Deserialize, Serialize};

fn get_setting(key: &str) -> Option<String> {
    let conn = pool().get().ok()?;
    conn.query_row(
        "SELECT value FROM settings WHERE key = ?1",
        params![key],
        |row| row.get::<_, String>(0),
    )
    .ok()
    .filter(|v| !v.is_empty())
}

fn home_dir() -> PathBuf {
    std::env::var("USERPROFILE")
        .or_else(|_| std::env::var("HOME"))
        .map(PathBuf::from)
        .unwrap_or_else(|_| PathBuf::from("C:\\Users\\default"))
}

const BLOCK_START: &str = "# ── DevManager:start ── 以下由炼境自动管理，请勿手动修改";
const BLOCK_END: &str = "# ── DevManager:end ──";

fn ssh_config_path() -> PathBuf {
    home_dir()
        .join(".ssh")
        .join("config")
}

/// 将服务器名转为 SSH config 合法的 Host 别名
/// 中文名用拼音首字母或直接用 server_host 的简化形式
fn to_host_alias(name: &str, host: &str) -> String {
    // 尝试从名称中提取 ASCII 字符
    let ascii_part: String = name
        .chars()
        .filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_')
        .collect();
    let alias = ascii_part.trim_matches('-').to_string();

    if alias.is_empty() {
        // 名称全是非 ASCII（如纯中文），用 host 的简化形式
        let host_alias: String = host
            .chars()
            .map(|c| if c.is_ascii_alphanumeric() || c == '-' { c } else { '-' })
            .collect();
        format!("dm-{}", host_alias.trim_matches('-'))
    } else {
        format!("dm-{}", alias)
    }
}

/// 生成炼境管理的 SSH Config 区块内容
fn generate_block(global_key: &Option<String>) -> Result<String, String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    let servers = list_servers(&conn);

    let mut lines = vec![BLOCK_START.to_string()];

    for s in &servers {
        let alias = to_host_alias(&s.name, &s.server_host);
        if alias == "dm-" || alias.is_empty() {
            continue; // 跳过无法生成有效别名的服务器
        }
        lines.push(format!("\nHost {}", alias));
        lines.push(format!("    HostName {}", s.server_host));
        if let Some(ref port) = s.server_port {
            if port != "22" {
                lines.push(format!("    Port {}", port));
            }
        }
        if let Some(ref user) = s.username {
            lines.push(format!("    User {}", user));
        }
        // 优先服务器级密钥，其次全局密钥
        let key = s.ssh_key_path.as_ref().or(global_key.as_ref());
        if let Some(k) = key {
            lines.push(format!("    IdentityFile {}", k));
        }
        lines.push("    StrictHostKeyChecking accept-new".to_string());
    }

    lines.push(String::new());
    lines.push(BLOCK_END.to_string());

    Ok(lines.join("\n"))
}

/// 同步 SSH Config 文件：替换 DevManager 管理的区块
#[tauri::command]
pub fn sync_ssh_config() -> Result<String, String> {
    let global_key = get_setting("ssh_key_path");
    let block = generate_block(&global_key)?;

    let config_path = ssh_config_path();

    // 确保 .ssh 目录存在
    if let Some(parent) = config_path.parent() {
        std::fs::create_dir_all(parent).map_err(|e| format!("无法创建 .ssh 目录: {e}"))?;
    }

    // 读取现有内容
    let existing = std::fs::read_to_string(&config_path).unwrap_or_default();

    // 替换或追加管理区块
    let new_content = if existing.contains(BLOCK_START) {
        let before = existing
            .split(BLOCK_START)
            .next()
            .unwrap_or("")
            .trim_end();
        let after = existing
            .split(BLOCK_END)
            .nth(1)
            .unwrap_or("")
            .trim_start();

        let mut result = before.to_string();
        if !result.is_empty() {
            result.push_str("\n\n");
        }
        result.push_str(&block);
        if !after.is_empty() {
            result.push_str("\n\n");
            result.push_str(after);
        }
        result
    } else {
        let mut result = existing.trim_end().to_string();
        if !result.is_empty() {
            result.push_str("\n\n");
        }
        result.push_str(&block);
        result.push('\n');
        result
    };

    std::fs::write(&config_path, &new_content)
        .map_err(|e| format!("写入 SSH Config 失败: {e}"))?;

    Ok(config_path.to_string_lossy().into_owned())
}

/// 获取 SSH Config 同步状态
#[tauri::command]
pub fn get_ssh_config_status() -> Result<SshConfigStatus, String> {
    let config_path = ssh_config_path();
    let exists = config_path.exists();
    let has_block = if exists {
        std::fs::read_to_string(&config_path)
            .map(|c| c.contains(BLOCK_START))
            .unwrap_or(false)
    } else {
        false
    };

    Ok(SshConfigStatus {
        config_path: config_path.to_string_lossy().into_owned(),
        file_exists: exists,
        has_devmanager_block: has_block,
    })
}

#[derive(Debug, Serialize)]
pub struct SshConfigStatus {
    pub config_path: String,
    pub file_exists: bool,
    pub has_devmanager_block: bool,
}

/// 检测 VS Code 环境
#[derive(Debug, Serialize)]
pub struct VscodeStatus {
    pub installed: bool,
    pub path: Option<String>,
    pub remote_ssh_hint: String,
}

#[tauri::command]
pub fn check_vscode_status() -> Result<VscodeStatus, String> {
    // 先检查炼境设置里有没有配置 VS Code
    let conn = pool().get().map_err(|e| e.to_string())?;
    let editors_json: Option<String> = conn
        .query_row("SELECT value FROM settings WHERE key = 'editors'", [], |r| r.get(0))
        .ok();

    let mut found_path: Option<String> = None;

    // 检查设置中的编辑器列表
    if let Some(ref json) = editors_json {
        if let Ok(editors) = serde_json::from_str::<Vec<serde_json::Value>>(json) {
            for ed in &editors {
                let name = ed.get("name").and_then(|v| v.as_str()).unwrap_or("");
                let path = ed.get("path").and_then(|v| v.as_str()).unwrap_or("");
                if name.to_lowercase().contains("vs code") || name.to_lowercase().contains("vscode") || path.to_lowercase().contains("code") {
                    if !path.is_empty() {
                        found_path = Some(path.to_string());
                        break;
                    }
                }
            }
        }
    }

    // 若设置中没有，尝试 where code
    if found_path.is_none() {
        let output = Command::new("cmd")
            .args(["/c", "where code 2>nul"])
            .output();
        if let Ok(out) = output {
            let stdout = String::from_utf8_lossy(&out.stdout);
            for line in stdout.lines() {
                let p = line.trim();
                if !p.is_empty() {
                    // where code 可能返回 .cmd 脚本，也算可用
                    found_path = Some(p.to_string());
                    break;
                }
            }
        }
    }

    // 若仍未找到，搜索常见安装路径
    if found_path.is_none() {
        let local_app = std::env::var("LOCALAPPDATA").unwrap_or_default();
        let candidates = [
            format!("{}\\Programs\\Microsoft VS Code\\Code.exe", local_app),
            "C:\\Program Files\\Microsoft VS Code\\Code.exe".to_string(),
            "C:\\Program Files (x86)\\Microsoft VS Code\\Code.exe".to_string(),
        ];
        for c in &candidates {
            if std::path::Path::new(c).exists() {
                found_path = Some(c.clone());
                break;
            }
        }
    }

    let installed = found_path.is_some();
    let hint = if !installed {
        "VS Code 未检测到。请在「设置」页面配置编辑器路径，或确保 code 命令在系统 PATH 中。".to_string()
    } else {
        "请确保已安装 Remote - SSH 扩展（扩展 ID: ms-vscode-remote.remote-ssh）".to_string()
    };

    Ok(VscodeStatus {
        installed,
        path: found_path,
        remote_ssh_hint: hint,
    })
}

/// 通过 VS Code Remote SSH 打开服务器
#[tauri::command]
pub fn open_vscode_remote(server_id: String, remote_path: Option<String>) -> Result<String, String> {
    let conn = pool().get().map_err(|e| e.to_string())?;

    // 先同步 SSH Config
    drop(conn);
    sync_ssh_config()?;

    let conn = pool().get().map_err(|e| e.to_string())?;

    // 获取服务器信息
    let server = crate::commands::servers::get_server(&conn, &server_id)
        .ok_or_else(|| format!("服务器不存在: {server_id}"))?;

    let alias = to_host_alias(&server.name, &server.server_host);
    let path = remote_path.unwrap_or_else(|| {
        if server.username.as_deref() == Some("root") {
            "/root".to_string()
        } else {
            format!("/home/{}", server.username.as_deref().unwrap_or("ubuntu"))
        }
    });

    // 查找 VS Code 路径
    let vscode_status = check_vscode_status()?;
    let code_path = vscode_status.path.ok_or(
        "VS Code 未找到。请在「设置」页面配置编辑器路径。".to_string()
    )?;

    // code --remote ssh-remote+{alias} {path}
    let remote_arg = format!("ssh-remote+{}", alias);

    // 如果路径是 .cmd 脚本或纯命令名，用 cmd /c 让 shell 解析
    // 如果是 .exe 路径，直接执行
    let is_exe = code_path.to_lowercase().ends_with(".exe");
    let spawn_result = if is_exe {
        Command::new(&code_path)
            .args(["--remote", &remote_arg, &path])
            .spawn()
    } else {
        // .cmd 或命令名（如 "code"），通过 cmd /c 执行
        Command::new("cmd")
            .args(["/c", &code_path, "--remote", &remote_arg, &path])
            .spawn()
    };

    spawn_result.map_err(|e| format!("无法启动 VS Code: {e}"))?;

    let cmd_str = format!("{} --remote {} {}", code_path, remote_arg, path);
    Ok(cmd_str)
}

/// 在 Windows Terminal 中打开 SSH 连接到服务器
#[tauri::command]
pub fn open_server_terminal(server_id: String) -> Result<String, String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    let server = crate::commands::servers::get_server(&conn, &server_id)
        .ok_or_else(|| format!("服务器不存在: {server_id}"))?;

    let port_flag = match server.server_port.as_deref() {
        Some(p) if p != "22" => format!(" -p {p}"),
        _ => String::new(),
    };
    let key_flag = match server.ssh_key_path.as_deref() {
        Some(k) if !k.is_empty() => format!(" -i {k}"),
        _ => {
            // 尝试全局 SSH key
            match get_setting("ssh_key_path") {
                Some(k) if !k.is_empty() => format!(" -i {k}"),
                _ => String::new(),
            }
        }
    };
    let user = server.username.as_deref().unwrap_or("root");
    let ssh_cmd = format!("ssh {user}@{}{port_flag}{key_flag}", server.server_host);

    // 用 Windows Terminal 新标签打开，标题设为服务器名称
    let title = format!("SSH: {}", server.name);
    let wt_args = vec![
        "-w".to_string(), "0".to_string(),
        "nt".to_string(),
        "--title".to_string(), title,
        "cmd".to_string(), "/k".to_string(), ssh_cmd.clone(),
    ];

    #[cfg(target_os = "windows")]
    let result = Command::new("cmd").args(["/c", "wt"]).args(&wt_args).spawn();

    #[cfg(not(target_os = "windows"))]
    let result = Command::new("wt").args(&wt_args).spawn();

    result.map_err(|e| format!("无法启动终端: {e}"))?;

    Ok(ssh_cmd)
}

// ── SSH Config 解析 & 导入 ──────────────────────────────────────────────────

/// 从 SSH Config 解析出的一个 Host 条目
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SshConfigEntry {
    pub host_alias: String,
    pub hostname: Option<String>,
    pub port: Option<String>,
    pub user: Option<String>,
    pub identity_file: Option<String>,
}

/// 解析 SSH Config 中非炼境管理的 Host 条目
#[tauri::command]
pub fn parse_ssh_config_entries() -> Result<Vec<SshConfigEntry>, String> {
    let config_path = ssh_config_path();
    let content = std::fs::read_to_string(&config_path)
        .map_err(|e| format!("无法读取 SSH Config: {e}"))?;

    let mut entries: Vec<SshConfigEntry> = Vec::new();
    let mut current: Option<SshConfigEntry> = None;
    let mut in_devmanager_block = false;

    for line in content.lines() {
        let trimmed = line.trim();

        // 跳过炼境管理区块
        if trimmed.contains("DevManager:start") {
            // 保存当前未完成的条目
            if let Some(entry) = current.take() {
                if entry.hostname.is_some() {
                    entries.push(entry);
                }
            }
            in_devmanager_block = true;
            continue;
        }
        if trimmed.contains("DevManager:end") {
            in_devmanager_block = false;
            continue;
        }
        if in_devmanager_block {
            continue;
        }

        // 跳过空行和注释
        if trimmed.is_empty() || trimmed.starts_with('#') {
            continue;
        }

        // 解析 Host 行
        if let Some(alias) = trimmed.strip_prefix("Host ").or_else(|| trimmed.strip_prefix("Host\t")) {
            // 保存上一个条目
            if let Some(entry) = current.take() {
                if entry.hostname.is_some() {
                    entries.push(entry);
                }
            }
            let alias = alias.trim().to_string();
            // 跳过通配符
            if alias.contains('*') || alias.contains('?') {
                continue;
            }
            current = Some(SshConfigEntry {
                host_alias: alias,
                hostname: None,
                port: None,
                user: None,
                identity_file: None,
            });
            continue;
        }

        // 解析属性行
        if let Some(ref mut entry) = current {
            let parts: Vec<&str> = trimmed.splitn(2, |c: char| c == ' ' || c == '\t').collect();
            if parts.len() == 2 {
                let key = parts[0].to_lowercase();
                let val = parts[1].trim().to_string();
                match key.as_str() {
                    "hostname" => entry.hostname = Some(val),
                    "port" => entry.port = Some(val),
                    "user" => entry.user = Some(val),
                    "identityfile" => entry.identity_file = Some(val),
                    _ => {}
                }
            }
        }
    }

    // 最后一个条目
    if let Some(entry) = current {
        if entry.hostname.is_some() {
            entries.push(entry);
        }
    }

    Ok(entries)
}

/// 将选中的 SSH Config 条目导入到 servers 表，然后重写 SSH Config
#[tauri::command]
pub fn import_ssh_config_entries(entries: Vec<SshConfigEntry>) -> Result<usize, String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    let mut imported = 0;

    for entry in &entries {
        let hostname = match &entry.hostname {
            Some(h) => h,
            None => continue,
        };

        // 检查是否已有相同 host 的服务器
        let exists: bool = conn
            .query_row(
                "SELECT 1 FROM servers WHERE server_host = ?1",
                params![hostname],
                |_| Ok(true),
            )
            .unwrap_or(false);
        if exists {
            continue;
        }

        let id = format!("srv-{}", uuid::Uuid::new_v4());
        conn.execute(
            "INSERT INTO servers (id, name, server_host, server_port, username, ssh_key_path)
             VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
            params![
                id,
                entry.host_alias,
                hostname,
                entry.port,
                entry.user,
                entry.identity_file,
            ],
        )
        .map_err(|e| e.to_string())?;
        imported += 1;
    }

    // 清理原 SSH Config 中已导入的手写条目，重写为纯炼境管理
    drop(conn);
    rewrite_ssh_config_clean()?;

    Ok(imported)
}

/// 重写 SSH Config：删除所有非炼境管理的条目（导入后调用）
fn rewrite_ssh_config_clean() -> Result<(), String> {
    let config_path = ssh_config_path();
    let content = std::fs::read_to_string(&config_path).unwrap_or_default();

    // 提取非 DevManager 区块的非 Host 内容（如全局配置）
    let mut global_lines: Vec<String> = Vec::new();
    let mut in_host = false;
    let mut in_devmanager_block = false;

    for line in content.lines() {
        let trimmed = line.trim();

        if trimmed.contains("DevManager:start") {
            in_devmanager_block = true;
            continue;
        }
        if trimmed.contains("DevManager:end") {
            in_devmanager_block = false;
            continue;
        }
        if in_devmanager_block {
            continue;
        }

        // 检测 Host 行
        if trimmed.starts_with("Host ") || trimmed.starts_with("Host\t") {
            in_host = true;
            continue;
        }

        // Host 内的属性行跳过
        if in_host && (trimmed.starts_with(' ') || trimmed.starts_with('\t') ||
            trimmed.to_lowercase().starts_with("hostname") ||
            trimmed.to_lowercase().starts_with("port") ||
            trimmed.to_lowercase().starts_with("user") ||
            trimmed.to_lowercase().starts_with("identityfile") ||
            trimmed.to_lowercase().starts_with("stricthostkeychecking")) {
            continue;
        }

        // 空行或注释 = Host 块结束
        if trimmed.is_empty() || trimmed.starts_with('#') {
            in_host = false;
        }

        if !in_host {
            global_lines.push(line.to_string());
        }
    }

    // 保留全局配置行（如果有的话）
    let global_part = global_lines.join("\n").trim().to_string();

    // 重新生成炼境区块
    let global_key = get_setting("ssh_key_path");
    let block = generate_block(&global_key)?;

    let mut result = String::new();
    if !global_part.is_empty() {
        result.push_str(&global_part);
        result.push_str("\n\n");
    }
    result.push_str(&block);
    result.push('\n');

    std::fs::write(&config_path, &result)
        .map_err(|e| format!("写入 SSH Config 失败: {e}"))?;

    Ok(())
}
