<?php
// admin/stats_snapshot_lib.php
// Snapshot واحد لعدادات المشتركين العامة حتى لا تطلب أكثر من واجهة نفس الإحصاءات من MikroTik في نفس الفترة.
// يبقي نفس شكل ua_unified_stats() تقريباً، لكنه يضيف كاش/قفل موحد لكل الشاشات.

if (!function_exists('ua_stats_snapshot_cache_dir')) {
  function ua_stats_snapshot_cache_dir(): string {
    $dir = __DIR__ . '/cache/runtime';
    if (!is_dir($dir)) @mkdir($dir, 0777, true);
    return $dir;
  }
}

if (!function_exists('ua_stats_snapshot_file')) {
  function ua_stats_snapshot_file(): string {
    return ua_stats_snapshot_cache_dir() . '/app_stats_snapshot.json';
  }
}

if (!function_exists('ua_stats_snapshot_lock_file')) {
  function ua_stats_snapshot_lock_file(): string {
    return ua_stats_snapshot_cache_dir() . '/app_stats_snapshot.lock';
  }
}

if (!function_exists('ua_stats_snapshot_default')) {
  function ua_stats_snapshot_default(): array {
    return [
      'ok' => false,
      'total' => 0,
      'online' => 0,
      'offline' => 0,
      'disabled' => 0,
      'financial_cut' => 0,
      'unsafe_speed' => 0,
      'open_all_mode' => 0,
      'ppp_active' => 0,
      'online_source' => 'snapshot_empty',
      'disabled_source' => 'snapshot_empty',
      'unsafe_source' => 'snapshot_empty',
      'updated_at' => date('Y-m-d H:i:s'),
      'snapshot_ts' => 0,
      'snapshot_age' => 999999,
      'snapshot_source' => 'empty',
      'reason' => 'empty_snapshot',
    ];
  }
}

if (!function_exists('ua_stats_snapshot_read')) {
  function ua_stats_snapshot_read(int $maxAge = 10): ?array {
    $file = ua_stats_snapshot_file();
    if (!is_file($file)) return null;
    $raw = @file_get_contents($file);
    $data = json_decode((string)$raw, true);
    if (!is_array($data)) return null;
    $ts = (int)($data['snapshot_ts'] ?? $data['ts'] ?? @filemtime($file));
    $age = $ts > 0 ? max(0, time() - $ts) : 999999;
    $data['snapshot_ts'] = $ts;
    $data['snapshot_age'] = $age;
    if ($age > max(1, $maxAge)) $data['snapshot_stale'] = 1;
    return $data;
  }
}

if (!function_exists('ua_stats_snapshot_write')) {
  function ua_stats_snapshot_write(array $data): bool {
    $now = time();
    $data['snapshot_ts'] = $now;
    $data['snapshot_age'] = 0;
    $data['snapshot_source'] = 'app_stats_snapshot';
    $data['ts'] = $now;
    $data['updated_at'] = (string)($data['updated_at'] ?? date('Y-m-d H:i:s'));
    $file = ua_stats_snapshot_file();
    $tmp = $file . '.tmp';
    $ok = @file_put_contents($tmp, json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT), LOCK_EX);
    if ($ok === false) return false;
    return @rename($tmp, $file);
  }
}

if (!function_exists('ua_stats_snapshot_lock_acquire')) {
  function ua_stats_snapshot_lock_acquire(int $ttl = 6) {
    $lock = ua_stats_snapshot_lock_file();
    if (is_file($lock) && (time() - (int)@filemtime($lock)) < max(2, $ttl)) return false;
    $fh = @fopen($lock, 'c+');
    if (!$fh) return false;
    if (!@flock($fh, LOCK_EX | LOCK_NB)) { @fclose($fh); return false; }
    @ftruncate($fh, 0);
    @fwrite($fh, (string)getmypid());
    @touch($lock);
    return $fh;
  }
}

if (!function_exists('ua_stats_snapshot_lock_release')) {
  function ua_stats_snapshot_lock_release($fh): void {
    if ($fh) { @flock($fh, LOCK_UN); @fclose($fh); }
  }
}

if (!function_exists('ua_stats_snapshot_build')) {
  function ua_stats_snapshot_build(mysqli $conn, int $ttl = 10, bool $forceRouterRefresh = false): array {
    require_once __DIR__ . '/ua_unified_stats_lib.php';
    $data = function_exists('ua_unified_stats') ? ua_unified_stats($conn, max(3, $ttl), $forceRouterRefresh) : ua_stats_snapshot_default();
    if (!is_array($data)) $data = ua_stats_snapshot_default();
    $data['ok'] = (bool)($data['ok'] ?? true);
    $data['ppp_active'] = (int)($data['ppp_active'] ?? $data['online'] ?? 0);
    $data['financial_cut'] = (int)($data['financial_cut'] ?? $data['disabled'] ?? 0);
    $data['offline'] = max(0, (int)($data['total'] ?? 0) - (int)($data['online'] ?? 0));
    $data['snapshot_built_at'] = date('Y-m-d H:i:s');
    return $data;
  }
}

if (!function_exists('ua_app_stats_snapshot')) {
  function ua_app_stats_snapshot(mysqli $conn, int $ttl = 10, bool $force = false): array {
    $ttl = max(3, (int)$ttl);
    if (!$force) {
      $cached = ua_stats_snapshot_read($ttl);
      if (is_array($cached) && empty($cached['snapshot_stale'])) {
        $cached['snapshot_source'] = (string)($cached['snapshot_source'] ?? 'app_stats_snapshot');
        return $cached;
      }
    } else {
      $cached = ua_stats_snapshot_read(86400);
    }

    $lock = ua_stats_snapshot_lock_acquire($ttl);
    if (!$lock) {
      // إذا طلبت واجهتان الإحصاءات بنفس اللحظة، الثانية تأخذ آخر snapshot بدل إعادة أوامر MikroTik.
      if (is_array($cached ?? null)) {
        $cached['snapshot_source'] = 'stale_app_stats_snapshot_locked';
        $cached['snapshot_age'] = (int)($cached['snapshot_age'] ?? 999999);
        return $cached;
      }
      return ua_stats_snapshot_default();
    }

    try {
      // فحص أخير بعد أخذ القفل؛ ربما طلب آخر سبقنا وبنى الكاش.
      if (!$force) {
        $fresh = ua_stats_snapshot_read($ttl);
        if (is_array($fresh) && empty($fresh['snapshot_stale'])) return $fresh;
      }
      // Rebuilding a stale application snapshot is the one acquisition point.
      // All UI endpoints consume this snapshot instead of independently probing
      // MikroTik or composing competing counters.
      $data = ua_stats_snapshot_build($conn, $ttl, true);
      ua_stats_snapshot_write($data);
      return ua_stats_snapshot_read(86400) ?: $data;
    } catch (Throwable $e) {
      $fallback = ua_stats_snapshot_read(86400);
      if (is_array($fallback)) {
        $fallback['ok'] = (bool)($fallback['ok'] ?? true);
        $fallback['snapshot_source'] = 'fallback_app_stats_snapshot_error';
        $fallback['reason'] = (string)$e->getMessage();
        return $fallback;
      }
      $d = ua_stats_snapshot_default();
      $d['reason'] = $e->getMessage();
      return $d;
    } finally {
      ua_stats_snapshot_lock_release($lock);
    }
  }
}

if (!function_exists('ua_app_stats_compact_counts')) {
  function ua_app_stats_compact_counts(array $s): array {
    return [
      'total' => (int)($s['total'] ?? 0),
      'online' => (int)($s['online'] ?? 0),
      'offline' => (int)($s['offline'] ?? 0),
      'disabled' => (int)($s['disabled'] ?? 0),
      'financial_cut' => (int)($s['financial_cut'] ?? $s['disabled'] ?? 0),
      'ppp_active' => (int)($s['ppp_active'] ?? $s['online'] ?? 0),
      'unsafe_speed' => (int)($s['unsafe_speed'] ?? 0),
      'open_all_mode' => (int)($s['open_all_mode'] ?? 0),
      'source' => (string)($s['snapshot_source'] ?? $s['online_source'] ?? 'app_stats_snapshot'),
      'age' => (int)($s['snapshot_age'] ?? 0),
      'router_online' => $s['router_online'] ?? null,
      'live_data_reliable' => !empty($s['live_data_reliable']),
      'data_available' => !empty($s['data_available']),
      'connection_state' => (string)($s['connection_state'] ?? 'unknown'),
      'data_age' => (int)($s['data_age'] ?? 0),
    ];
  }
}
