updt 0.1.45

Cross-platform update helper for npm, cargo, rustup, fnm, scoop, Homebrew, paru, flatpak, pacman, and pkg.
use std::env;
use std::io::{self, IsTerminal};
use tokio::fs;

use crate::state::{AppState, SystemProfile};

pub async fn parse_profile(state: &mut AppState) {
    let prefix = env::var("PREFIX").unwrap_or_default();
    state.enable.nvim = true;
    state.is_termux = prefix.contains("com.termux")
        || fs::metadata("/data/data/com.termux/files/usr/bin/pkg")
            .await
            .is_ok();
    state.is_arch_linux = fs::metadata("/etc/arch-release").await.is_ok();
    apply_profile_policy(state, detect_profile(state.is_termux, state.is_arch_linux));
}

struct ProfileRule {
    profile: SystemProfile,
    matches: fn(bool, bool) -> bool,
    apply: fn(&mut AppState),
}

const PROFILE_RULES: &[ProfileRule] = &[
    ProfileRule {
        profile: SystemProfile::Termux,
        matches: is_termux_profile,
        apply: apply_termux_policy,
    },
    ProfileRule {
        profile: SystemProfile::Windows,
        matches: is_windows_profile,
        apply: apply_windows_policy,
    },
    ProfileRule {
        profile: SystemProfile::Macos,
        matches: is_macos_profile,
        apply: apply_macos_policy,
    },
    ProfileRule {
        profile: SystemProfile::Arch,
        matches: is_arch_profile,
        apply: apply_arch_policy,
    },
];

fn detect_profile(is_termux: bool, is_arch_linux: bool) -> SystemProfile {
    PROFILE_RULES
        .iter()
        .find(|rule| (rule.matches)(is_termux, is_arch_linux))
        .map(|rule| rule.profile)
        .unwrap_or_default()
}

fn apply_profile_policy(state: &mut AppState, profile: SystemProfile) {
    state.system_profile = profile;
    if let Some(rule) = PROFILE_RULES.iter().find(|rule| rule.profile == profile) {
        (rule.apply)(state);
    }
}

fn is_termux_profile(is_termux: bool, _is_arch_linux: bool) -> bool {
    is_termux
}

fn is_windows_profile(is_termux: bool, _is_arch_linux: bool) -> bool {
    !is_termux && env::consts::OS == "windows"
}

fn is_macos_profile(is_termux: bool, _is_arch_linux: bool) -> bool {
    !is_termux && env::consts::OS == "macos"
}

fn is_arch_profile(is_termux: bool, is_arch_linux: bool) -> bool {
    !is_termux && is_arch_linux
}

fn apply_termux_policy(state: &mut AppState) {
    state.enable.pkg = true;
    state.enable.npm = true;
    state.enable.cargo = true;
    state.enable.fnm = true;
    state.enable.rustup = false;
}

fn apply_windows_policy(state: &mut AppState) {
    state.enable.npm = true;
    state.enable.cargo = true;
    state.enable.rustup = true;
    state.enable.fnm = true;
    state.enable.scoop = true;
}

fn apply_macos_policy(state: &mut AppState) {
    state.enable.brew = true;
    state.enable.npm = true;
    state.enable.cargo = true;
    state.enable.rustup = true;
    state.enable.fnm = true;
}

fn apply_arch_policy(state: &mut AppState) {
    state.enable.npm = true;
    state.enable.cargo = true;
    state.enable.rustup = true;
    state.enable.fnm = true;
    state.enable.paru = true;
    state.enable.pacman = true;
    state.enable.flatpak = true;
}

pub fn interactive_terminal() -> bool {
    io::stdout().is_terminal() && io::stdin().is_terminal()
}

pub fn desktop_linux_session() -> bool {
    env::consts::OS == "linux"
        && [
            "DISPLAY",
            "WAYLAND_DISPLAY",
            "XDG_CURRENT_DESKTOP",
            "DESKTOP_SESSION",
        ]
        .iter()
        .any(|key| env::var_os(key).is_some_and(|value| !value.is_empty()))
}