<?php

/**
 * Simple file-based page cache for guest (not-logged-in) article pages.
 * Invalidated by bumping the version file when articles are created/updated/deleted.
 */
class ArticleCache
{
    private const DIR = '/storage/cache/articles';
    private const TTL = 300; // 5 minutes
    private const VERSION_FILE = '/storage/cache/articles/.version';

    private static function baseDir(): string
    {
        $dir = APP_ROOT . self::DIR;
        if (!is_dir($dir)) @mkdir($dir, 0755, true);
        return $dir;
    }

    public static function version(): string
    {
        $f = APP_ROOT . self::VERSION_FILE;
        if (!file_exists($f)) {
            @file_put_contents($f, (string)time());
        }
        return trim((string)@file_get_contents($f));
    }

    public static function bumpVersion(): void
    {
        self::baseDir();
        @file_put_contents(APP_ROOT . self::VERSION_FILE, (string)microtime(true));
    }

    private static function key(string $ns, array $parts): string
    {
        $parts['__v'] = self::version();
        ksort($parts);
        return $ns . '_' . md5(http_build_query($parts));
    }

    public static function get(string $ns, array $parts): ?string
    {
        $file = self::baseDir() . '/' . self::key($ns, $parts);
        if (!file_exists($file)) return null;
        if ((time() - filemtime($file)) > self::TTL) {
            @unlink($file);
            return null;
        }
        $content = @file_get_contents($file);
        return $content !== false ? $content : null;
    }

    public static function put(string $ns, array $parts, string $content): void
    {
        $file = self::baseDir() . '/' . self::key($ns, $parts);
        @file_put_contents($file, $content, LOCK_EX);
    }

    public static function sendEtag(string $etag, ?string $lastModified = null, int $maxAge = 300): bool
    {
        header('ETag: "' . $etag . '"');
        if ($lastModified) {
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s', strtotime($lastModified)) . ' GMT');
        }
        header('Cache-Control: public, max-age=' . $maxAge . ', s-maxage=' . ($maxAge * 12) . ', stale-while-revalidate=86400');

        $inm = $_SERVER['HTTP_IF_NONE_MATCH'] ?? '';
        if ($inm && trim($inm, '"') === $etag) {
            http_response_code(304);
            return true;
        }
        $ims = $_SERVER['HTTP_IF_MODIFIED_SINCE'] ?? '';
        if ($lastModified && $ims && strtotime($ims) >= strtotime($lastModified)) {
            http_response_code(304);
            return true;
        }
        return false;
    }
}
