use super::super::models::types::{ExecRequest, SystemProfile};
use super::{
    normalize_optional, posix_build_exec_command, RemoteShell, SystemProfileCommands,
    SystemProfileOutputs, SystemType,
};

pub(crate) struct PosixMacOsShell;

impl RemoteShell for PosixMacOsShell {
    fn system_type(&self) -> SystemType {
        SystemType::MacOs
    }

    fn build_exec_command(&self, req: &ExecRequest) -> String {
        posix_build_exec_command(req)
    }

    fn build_system_profile_commands(&self) -> SystemProfileCommands {
        SystemProfileCommands {
            os_info: ExecRequest {
                command: "sw_vers".to_string(),
                use_shell: true,
                ..ExecRequest::default()
            },
            arch: ExecRequest {
                command: "uname -m".to_string(),
                use_shell: true,
                ..ExecRequest::default()
            },
            shell: ExecRequest {
                command: "printf %s \"$SHELL\"".to_string(),
                use_shell: true,
                ..ExecRequest::default()
            },
            package_manager: ExecRequest {
                command: "command -v brew".to_string(),
                use_shell: true,
                ..ExecRequest::default()
            },
        }
    }

    fn parse_system_profile(&self, outputs: &SystemProfileOutputs) -> SystemProfile {
        let (os_id, os_version) = parse_sw_vers(&outputs.os_info);

        SystemProfile {
            os_id,
            os_version,
            arch: normalize_optional(&outputs.arch),
            package_manager: normalize_package_manager(&outputs.package_manager),
            shell: normalize_optional(&outputs.shell),
        }
    }
}

fn parse_sw_vers(content: &str) -> (Option<String>, Option<String>) {
    let mut os_id = None;
    let mut os_version = None;

    for line in content.lines() {
        let trimmed = line.trim();
        if let Some((key, value)) = trimmed.split_once(':') {
            match key.trim() {
                "ProductName" => os_id = Some(value.trim().to_lowercase()),
                "ProductVersion" => os_version = Some(value.trim().to_string()),
                _ => {}
            }
        }
    }

    (os_id, os_version)
}

fn normalize_package_manager(probe_output: &str) -> Option<String> {
    let trimmed = probe_output.trim();
    if trimmed.is_empty() {
        None
    } else if trimmed.contains("brew") {
        Some("brew".to_string())
    } else {
        Some(trimmed.to_string())
    }
}
