<?php

namespace App\Services;

use App\Models\Device;

class PingService
{
    /**
     * Ping a device and return ['online'=>bool, 'latency_ms'=>int|null, 'message'=>string]
     */
    public static function ping(Device $device): array
    {
        $ip    = escapeshellarg($device->ip_address);
        $start = microtime(true);

        // Try TCP connection first (more reliable than ICMP ping in hosted envs)
        $sock = @fsockopen($device->ip_address, $device->port, $errno, $errstr, 3);
        if ($sock) {
            fclose($sock);
            $ms = (int) round((microtime(true) - $start) * 1000);
            return ['online' => true, 'latency_ms' => $ms, 'message' => "TCP port {$device->port} open"];
        }

        // Fallback: ICMP ping
        $output = [];
        @exec("ping -c 1 -W 2 {$ip} 2>&1", $output, $code);
        $ms = null;

        if ($code === 0) {
            // Try to parse latency from ping output
            foreach ($output as $line) {
                if (preg_match('/time[=<]([\d.]+)\s*ms/i', $line, $m)) {
                    $ms = (int) round((float) $m[1]);
                    break;
                }
            }
            return ['online' => true, 'latency_ms' => $ms, 'message' => 'ICMP reachable'];
        }

        return [
            'online'     => false,
            'latency_ms' => null,
            'message'    => "Unreachable — $errstr ($errno)",
        ];
    }

    /** Ping all active devices and update their last_status in the DB. */
    public static function pingAll(): array
    {
        $devices = Device::where('is_active', true)->get();
        $results = [];

        foreach ($devices as $device) {
            $r = self::ping($device);
            $device->update([
                'last_status'  => $r['online'] ? 'online' : 'offline',
                'last_seen_at' => $r['online'] ? now() : $device->last_seen_at,
            ]);
            $results[] = array_merge(['device' => $device], $r);
        }

        return $results;
    }
}
