#[cfg(target_os = "linux")]
fn linux_service_unit_path() -> PathBuf {
    PathBuf::from(format!("/etc/systemd/system/{LINUX_SERVICE_UNIT_NAME}"))
}

#[cfg(any(target_os = "linux", test))]
pub(crate) fn linux_service_binary_path() -> PathBuf {
    PathBuf::from("/usr/local/bin/nvpn")
}

#[cfg(target_os = "linux")]
fn linux_install_service(
    executable: &Path,
    config_path: &Path,
    iface: &str,
    mesh_refresh_interval_secs: u64,
    log_path: &Path,
    force: bool,
) -> Result<()> {
    if !linux_systemctl_available() {
        return Err(anyhow!("systemd (systemctl) is not available on this host"));
    }

    let unit_path = linux_service_unit_path();
    if unit_path.exists() && !force {
        println!(
            "service already installed at {} (pass --force to reinstall)",
            unit_path.display()
        );
        return Ok(());
    }

    let _ = run_systemctl_allow_missing(
        &["disable", "--now", LINUX_SERVICE_UNIT_NAME],
        "disable/stop existing service",
        true,
    );
    stop_existing_daemons_before_service_install(config_path)?;
    let service_executable = linux_service_binary_path();
    install_service_executable_copy(executable, &service_executable)?;
    let unit = linux_service_unit_content(
        &service_executable,
        config_path,
        iface,
        mesh_refresh_interval_secs,
        log_path,
    );
    let temp = unit_path.with_extension(format!("tmp-{}", std::process::id()));
    fs::write(&temp, unit).with_context(|| format!("failed to write {}", temp.display()))?;
    #[cfg(unix)]
    fs::set_permissions(&temp, fs::Permissions::from_mode(0o644))
        .with_context(|| format!("failed to chmod {}", temp.display()))?;
    fs::rename(&temp, &unit_path).with_context(|| {
        format!(
            "failed to move {} into {}",
            temp.display(),
            unit_path.display()
        )
    })?;

    run_systemctl_checked(&["daemon-reload"], "reload systemd")?;
    run_systemctl_checked(
        &["enable", "--now", LINUX_SERVICE_UNIT_NAME],
        "enable/start service",
    )?;
    println!("installed system service: {}", unit_path.display());
    println!("label: {LINUX_SERVICE_UNIT_NAME}");
    Ok(())
}

#[cfg(target_os = "linux")]
fn linux_uninstall_service() -> Result<()> {
    if !linux_systemctl_available() {
        return Err(anyhow!("systemd (systemctl) is not available on this host"));
    }

    run_systemctl_allow_missing(
        &["disable", "--now", LINUX_SERVICE_UNIT_NAME],
        "disable/stop service",
        true,
    )?;

    let unit_path = linux_service_unit_path();
    if unit_path.exists() {
        fs::remove_file(&unit_path)
            .with_context(|| format!("failed to remove {}", unit_path.display()))?;
        println!("removed system service unit: {}", unit_path.display());
    } else {
        println!("system service unit not found: {}", unit_path.display());
    }

    run_systemctl_checked(&["daemon-reload"], "reload systemd")?;
    Ok(())
}

#[cfg(target_os = "linux")]
fn linux_query_service_status(include_binary_version: bool) -> Result<ServiceStatusView> {
    let unit_path = linux_service_unit_path();
    let installed = unit_path.exists();
    let service_binary = linux_service_executable_path(&unit_path);
    let binary_version = if include_binary_version {
        service_binary
            .as_ref()
            .and_then(|path| query_binary_version(path))
            .unwrap_or_default()
    } else {
        String::new()
    };
    if !linux_systemctl_available() {
        return Ok(ServiceStatusView {
            supported: false,
            installed,
            disabled: false,
            loaded: false,
            running: false,
            pid: None,
            label: LINUX_SERVICE_UNIT_NAME.to_string(),
            plist_path: unit_path.display().to_string(),
            binary_path: service_binary
                .map(|path| path.display().to_string())
                .unwrap_or_default(),
            binary_version,
        });
    }

    let output = run_systemctl_raw(
        &[
            "show",
            LINUX_SERVICE_UNIT_NAME,
            "--property=LoadState,ActiveState,SubState,MainPID",
            "--no-pager",
        ],
        "query service",
    )?;

    if !output.status.success() {
        return Ok(ServiceStatusView {
            supported: true,
            installed,
            disabled: false,
            loaded: false,
            running: false,
            pid: None,
            label: LINUX_SERVICE_UNIT_NAME.to_string(),
            plist_path: unit_path.display().to_string(),
            binary_path: service_binary
                .map(|path| path.display().to_string())
                .unwrap_or_default(),
            binary_version,
        });
    }

    let show = String::from_utf8_lossy(&output.stdout);
    let (loaded, running, pid) = linux_service_status_from_show_output(&show);

    Ok(ServiceStatusView {
        supported: true,
        installed,
        disabled: false,
        loaded,
        running,
        pid,
        label: LINUX_SERVICE_UNIT_NAME.to_string(),
        plist_path: unit_path.display().to_string(),
        binary_path: service_binary
            .map(|path| path.display().to_string())
            .unwrap_or_default(),
        binary_version,
    })
}

#[cfg(target_os = "linux")]
fn linux_service_executable_path(unit_path: &Path) -> Option<PathBuf> {
    let unit = fs::read_to_string(unit_path).ok()?;
    linux_service_executable_path_from_unit_contents(&unit).map(PathBuf::from)
}

#[cfg(any(target_os = "linux", test))]
pub(crate) fn linux_service_executable_path_from_unit_contents(unit: &str) -> Option<String> {
    for line in unit.lines() {
        let Some(command) = line.trim().strip_prefix("ExecStart=") else {
            continue;
        };
        if let Some(quoted) = command.strip_prefix('"') {
            let executable = quoted.split_once('"')?.0;
            if !executable.trim().is_empty() {
                return Some(executable.to_string());
            }
        }
        let executable = command.split_whitespace().next()?.trim();
        if !executable.is_empty() {
            return Some(executable.to_string());
        }
    }
    None
}

#[cfg(any(target_os = "linux", test))]
pub(crate) fn linux_service_unit_content(
    executable: &Path,
    config_path: &Path,
    iface: &str,
    mesh_refresh_interval_secs: u64,
    log_path: &Path,
) -> String {
    let exec = systemd_quote(&executable.display().to_string());
    let config = systemd_quote(&config_path.display().to_string());
    let iface = systemd_quote(iface);
    let log = log_path.display().to_string();
    format!(
        "[Unit]\nDescription=Nostr VPN daemon\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart={exec} daemon --service --config {config} --iface {iface} --mesh-refresh-interval-secs {mesh_refresh_interval_secs}\nRestart=always\nRestartSec=3\nStandardOutput=append:{log}\nStandardError=append:{log}\n\n[Install]\nWantedBy=multi-user.target\n"
    )
}

#[cfg(target_os = "linux")]
fn linux_systemctl_available() -> bool {
    ProcessCommand::new("systemctl")
        .arg("--version")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .status()
        .map(|status| status.success())
        .unwrap_or(false)
}

#[cfg(target_os = "linux")]
fn run_systemctl_checked(args: &[&str], context: &str) -> Result<()> {
    let output = run_systemctl_raw(args, context)?;
    if output.status.success() {
        return Ok(());
    }

    let stderr = String::from_utf8_lossy(&output.stderr);
    let stdout = String::from_utf8_lossy(&output.stdout);
    Err(anyhow!(
        "systemctl {context} failed\nstdout: {}\nstderr: {}",
        stdout.trim(),
        stderr.trim()
    ))
}

#[cfg(target_os = "linux")]
fn run_systemctl_allow_missing(args: &[&str], context: &str, ignore_missing: bool) -> Result<()> {
    let output = run_systemctl_raw(args, context)?;
    if output.status.success() {
        return Ok(());
    }

    let stderr = String::from_utf8_lossy(&output.stderr);
    let stdout = String::from_utf8_lossy(&output.stdout);
    let details = format!("{}\n{}", stdout.trim(), stderr.trim());
    if ignore_missing && systemctl_missing_service_message(&details) {
        return Ok(());
    }

    Err(anyhow!(
        "systemctl {context} failed\nstdout: {}\nstderr: {}",
        stdout.trim(),
        stderr.trim()
    ))
}

#[cfg(target_os = "linux")]
fn run_systemctl_raw(args: &[&str], context: &str) -> Result<std::process::Output> {
    ProcessCommand::new("systemctl")
        .args(args)
        .output()
        .with_context(|| format!("failed to systemctl {context}"))
}

#[cfg(target_os = "linux")]
fn systemctl_missing_service_message(details: &str) -> bool {
    let lowered = details.to_ascii_lowercase();
    lowered.contains("could not be found")
        || lowered.contains("not loaded")
        || lowered.contains("no such file")
}

#[cfg(any(target_os = "linux", test))]
pub(crate) fn linux_service_status_from_show_output(show: &str) -> (bool, bool, Option<u32>) {
    let mut load_state = None;
    let mut active_state = None;
    let mut sub_state = None;
    let mut pid = None;

    for line in show.lines() {
        if let Some(value) = line.strip_prefix("LoadState=") {
            load_state = Some(value.trim().to_string());
        } else if let Some(value) = line.strip_prefix("ActiveState=") {
            active_state = Some(value.trim().to_string());
        } else if let Some(value) = line.strip_prefix("SubState=") {
            sub_state = Some(value.trim().to_string());
        } else if let Some(value) = line.strip_prefix("MainPID=") {
            pid = parse_nonzero_pid(value);
        }
    }

    let loaded = load_state.as_deref() == Some("loaded");
    let running =
        active_state.as_deref() == Some("active") && sub_state.as_deref() == Some("running");
    (loaded, running, pid)
}
