<?php
/* ============================================================
   count.php - Tiny JSON endpoint for the live on-site counter.

   Returns the number of unique visitors (distinct IPs) seen in
   the last 60 minutes, excluding own_ips.php. Deliberately cheap:
   the result is cached to disk for a few seconds so a burst of
   visitors polling at once triggers at most one CSV scan.

   Response:  {"visitors": 3, "visits": 11, "window_minutes": 60}
   ============================================================ */

header('Content-Type: application/json');
header('Cache-Control: no-store');

const WINDOW_SECS = 3600;     // "last 60 minutes"
const CACHE_SECS  = 15;       // serve a cached count for this long

$csv       = __DIR__ . '/visits.csv';
$cacheFile = __DIR__ . '/count-cache.json';
$exclude   = require __DIR__ . '/own_ips.php';

/* ---- serve fresh-enough cache without touching the CSV ---- */
if (is_readable($cacheFile) && (time() - filemtime($cacheFile)) < CACHE_SECS) {
    echo file_get_contents($cacheFile);
    exit;
}

function ip_in_cidr(string $ip, string $cidr): bool {
    if (strpos($cidr, '/') === false) return $ip === $cidr;
    [$subnet, $bits] = explode('/', $cidr, 2);
    $bits = (int)$bits;
    $ipB = @inet_pton($ip); $subB = @inet_pton($subnet);
    if ($ipB === false || $subB === false || strlen($ipB) !== strlen($subB)) return false;
    $bytes = intdiv($bits, 8); $rem = $bits % 8;
    if ($bytes && strncmp($ipB, $subB, $bytes) !== 0) return false;
    if ($rem) {
        $mask = chr(0xff << (8 - $rem) & 0xff);
        if ((ord($ipB[$bytes]) & ord($mask)) !== (ord($subB[$bytes]) & ord($mask))) return false;
    }
    return true;
}
function excluded(string $ip, array $rules): bool {
    foreach ($rules as $r) if (ip_in_cidr($ip, $r)) return true;
    return false;
}

$visits = 0; $ips = [];
$cutoff = time() - WINDOW_SECS;

if (is_readable($csv) && ($fh = fopen($csv, 'r')) !== false) {
    fgetcsv($fh); // header
    while (($r = fgetcsv($fh)) !== false) {
        if (count($r) < 2) continue;
        $ts = strtotime($r[0]);
        if ($ts === false || $ts < $cutoff) continue;
        $ip = $r[1];
        if ($ip === '' || excluded($ip, $exclude)) continue;
        $visits++;
        $ips[$ip] = true;
    }
    fclose($fh);
}

$out = json_encode([
    'visitors'       => count($ips),
    'visits'         => $visits,
    'window_minutes' => (int)(WINDOW_SECS / 60),
]);

@file_put_contents($cacheFile, $out, LOCK_EX);
echo $out;
