#!/usr/bin/env perl
# sysinfo.pl — Read-only system information collector for sysops
# Supports macOS (Darwin) and Linux. No destructive operations. No sudo.

use strict;
use warnings;
use POSIX qw(strftime);
use File::Basename;

my $OS = $^O;          # 'darwin' on macOS, 'linux' on Linux
my $sep = "=" x 72;

# ── helpers ──────────────────────────────────────────────────────────────
sub section {
    my ($title) = @_;
    print "\n$sep\n  $title\n$sep\n";
}

sub run {
    my ($cmd) = @_;
    my $out = `$cmd 2>/dev/null`;
    return defined $out ? $out : "(command not available)\n";
}

sub run_lines {
    my ($cmd) = @_;
    my $out = run($cmd);
    return grep { $_ ne "\n" } split /\n/, $out;
}

# ── header ───────────────────────────────────────────────────────────────
print "\n";
print "  ┌─────────────────────────────────────────────────────────┐\n";
print "  │          SYSTEM INFORMATION REPORT                      │\n";
print "  │          Generated: ", scalar(localtime), "          │\n";
print "  └─────────────────────────────────────────────────────────┘\n";

# ── OS / Hostname ────────────────────────────────────────────────────────
section "OS & Hostname";
if ($OS eq 'darwin') {
    print "  OS:       macOS (Darwin)\n";
    print "  Hostname: ", run("hostname -s"),;
    print "  Kernel:   ", run("uname -r"),;
    print "  Machine:  ", run("uname -m"),;
    print "  Build:    ", run("sw_vers -buildVersion"),;
} else {
    print "  OS:       Linux\n";
    print "  Hostname: ", run("hostname -s"),;
    print "  Kernel:   ", run("uname -r"),;
    print "  Machine:  ", run("uname -m"),;
    if (-f "/etc/os-release") {
        my @lines = run_lines('grep -E "^PRETTY_NAME=" /etc/os-release');
        print "  Distro:   ", ($lines[0] || "(unknown)"), "\n";
    } else {
        print "  Distro:   (unknown)\n";
    }
}

# ── Uptime & Load ────────────────────────────────────────────────────────
section "Uptime & Load";
if ($OS eq 'darwin') {
    print "  Uptime:   ", run("uptime"),;
} else {
    print "  Uptime:   ", run("uptime -p"),;
    print "  Load avg: ", run("cat /proc/loadavg"), "\n";
}

# ── CPU ──────────────────────────────────────────────────────────────────
section "CPU";
if ($OS eq 'darwin') {
    print "  Model:    ", run("sysctl -n machdep.cpu.brand_string"),;
    print "  Cores:    ", run("sysctl -n hw.ncpu"), " (logical)\n";
} else {
    my $cores = run("nproc 2>/dev/null || grep -c ^processor /proc/cpuinfo");
    print "  Cores:    $cores\n";
    if (open my $fh, "<", "/proc/cpuinfo") {
        while (<$fh>) {
            if (/^model name\s*:\s*(.+)/) {
                print "  Model:    $1\n";
                last;
            }
        }
        close $fh;
    }
}

# ── Memory ───────────────────────────────────────────────────────────────
section "Memory";
if ($OS eq 'darwin') {
    my $total = run("sysctl -n hw.memsize");
    $total =~ s/\s//g;
    print "  Total:    ", sprintf("%.2f GB", $total / (1024**3)), "\n";
    my $raw = run("ps -eo pid,pcpu,pmem,comm -k pmem -r 2>/dev/null | head -11");
    my @ps = grep { $_ ne "\n" } split /\n/, $raw;
    print "  Top 10 by memory:\n";
    for my $line (@ps) {
        next if $line =~ /^\s*(PID|^\s*$)/;
        my @f = split /\s+/, $line;
        next unless @f >= 4;
        printf "    %6s  %5s  %8s  %s\n", $f[0], $f[2] . "%", $f[1], $f[3];
    }
} else {
    my $total = run("grep MemTotal /proc/meminfo");
    $total =~ s/.*:\s*//;
    print "  Total:    ", sprintf("%.2f GB", $total / 1024 / 1024), "\n";
    my $free = run("grep MemFree /proc/meminfo");
    $free =~ s/.*:\s*//;
    print "  Free:     ", sprintf("%.2f GB", $free / 1024 / 1024), "\n";
    my $avail = run("grep MemAvailable /proc/meminfo");
    $avail =~ s/.*:\s*//;
    print "  Available:", sprintf("%.2f GB", $avail / 1024 / 1024), "\n";
    my @ps = run_lines("ps aux --sort=-%mem | head -11");
    print "  Top 10 by memory:\n";
    for my $line (@ps) {
        next if $line =~ /^\s*(USER|^\s*$)/;
        my @f = split /\s+/, $line;
        next unless @f >= 11;
        printf "    %6s  %5s  %8s  %s\n", $f[2], $f[3] . "%", $f[5], $f[10];
    }
}

# ── Disk ─────────────────────────────────────────────────────────────────
section "Disk";
if ($OS eq 'darwin') {
    print run("df -h / 2>/dev/null");
    print "\n  Filesystems:\n", run("diskutil list 2>/dev/null | head -30");
} else {
    print run("df -h 2>/dev/null");
    print "\n  Mount info:\n", run("findmnt --noheadings 2>/dev/null | head -20");
}

# ── Network ──────────────────────────────────────────────────────────────
section "Network";
if ($OS eq 'darwin') {
    print "  Interfaces:\n", run("ifconfig 2>/dev/null | grep -E '^[a-z]|inet '");
    print "  Default GW: ", run("netstat -rn 2>/dev/null | awk '/^default/ {print \$2}'"), "\n";
} else {
    print "  Interfaces:\n", run("ip -br addr 2>/dev/null || ifconfig 2>/dev/null");
    print "  Default GW: ", run("ip route show default 2>/dev/null | head -1"), "\n";
    print "  DNS:\n", run("cat /etc/resolv.conf 2>/dev/null");
}

# ── Processes (top by CPU) ───────────────────────────────────────────────
section "Top Processes (by CPU)";
if ($OS eq 'darwin') {
    print run("ps -eo pid,pcpu,pmem,comm -r | head -11");
} else {
    print run("ps aux --sort=-%cpu | head -11");
}

# ── Listening Ports ──────────────────────────────────────────────────────
section "Listening TCP Ports";
if ($OS eq 'darwin') {
    print run("lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null | head -25");
} else {
    print run("ss -tlnp 2>/dev/null | head -25 || netstat -tlnp 2>/dev/null | head -25");
}

# ── Recent system logs (last 10 lines) ───────────────────────────────────
section "Recent System Log (last 10 lines)";
if ($OS eq 'darwin') {
    print run("log show --predicate 'eventMessage contains \"error\" or eventMessage contains \"warn\"' --last 1h 2>/dev/null | tail -10");
    print run("tail -10 /var/log/system.log 2>/dev/null || (echo '(no system.log available)')");
} else {
    print run("journalctl -p err --no-pager -n 10 2>/dev/null || tail -10 /var/log/syslog 2>/dev/null || (echo '(no syslog available)')");
}

# ── Footer ───────────────────────────────────────────────────────────────
print "\n$sep\n  Report complete. No destructive operations were performed.\n$sep\n\n";

exit 0;
