<?php

/**
 * SystemCache — thin TTL cache for admin system page checks.
 *
 * Stores JSON-encoded data blobs in the `system_cache` SQLite table.
 * The table has a single schema:
 *   key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at INTEGER NOT NULL
 *
 * Usage:
 *   $cache = new SystemCache($pdo);
 *
 *   // Read (returns array or null if stale/missing)
 *   $data = $cache->get('system_status', 120);
 *
 *   // Write
 *   $cache->set('system_status', $myArray);
 *
 *   // Check freshness without reading value
 *   if ($cache->isStale('disk_info', 300)) { ... }
 *
 *   // Force-invalidate a key (e.g. on ?refresh=1)
 *   $cache->invalidate('system_status');
 */
class SystemCache
{
    private PDO $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    /**
     * Return cached data for $key if it is no older than $maxAgeSec seconds.
     * Returns null when the entry is missing or stale.
     */
    public function get(string $key, int $maxAgeSec = 60): ?array
    {
        $stmt = $this->pdo->prepare(
            'SELECT value, updated_at FROM system_cache WHERE key = ?'
        );
        $stmt->execute([$key]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return null;
        }

        if ((time() - (int)$row['updated_at']) > $maxAgeSec) {
            return null; // stale
        }

        $decoded = json_decode((string)$row['value'], true);
        return is_array($decoded) ? $decoded : null;
    }

    /**
     * Upsert $data (JSON-encoded) for $key with current timestamp.
     */
    public function set(string $key, array $data): void
    {
        $stmt = $this->pdo->prepare(
            'INSERT INTO system_cache (key, value, updated_at)
             VALUES (?, ?, ?)
             ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at'
        );
        $stmt->execute([$key, json_encode($data), time()]);
    }

    /**
     * Return true when the entry is missing or older than $maxAgeSec.
     */
    public function isStale(string $key, int $maxAgeSec = 60): bool
    {
        $stmt = $this->pdo->prepare(
            'SELECT updated_at FROM system_cache WHERE key = ?'
        );
        $stmt->execute([$key]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return true;
        }

        return (time() - (int)$row['updated_at']) > $maxAgeSec;
    }

    /**
     * Return the age of the cached entry in seconds, or null if missing.
     */
    public function ageSeconds(string $key): ?int
    {
        $stmt = $this->pdo->prepare(
            'SELECT updated_at FROM system_cache WHERE key = ?'
        );
        $stmt->execute([$key]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        return $row ? (time() - (int)$row['updated_at']) : null;
    }

    /**
     * Delete a cached entry, forcing the next get() to re-compute.
     */
    public function invalidate(string $key): void
    {
        $stmt = $this->pdo->prepare('DELETE FROM system_cache WHERE key = ?');
        $stmt->execute([$key]);
    }
}
