<?php
/**
 * File Cache Fallback
 *
 * Provides file-based caching as a fallback when persistent object cache
 * (Redis/Memcached) is not available.
 *
 * @package Mamba\Support
 * @since   1.0.0
 */

namespace Mamba\Support;

/**
 * Class FileCache
 *
 * File-based cache implementation that stores data in JSON files.
 * Used as fallback when no persistent object cache is available.
 *
 * @since 1.0.0
 */
final class FileCache {
    
    /**
     * Get base cache directory
     */
    private static function base(): string {
        // Safety check for WordPress constants and functions
        if (!defined('WP_CONTENT_DIR') || !function_exists('wp_mkdir_p')) {
            return '';
        }
        
        $dir = WP_CONTENT_DIR . '/cache/mamba/object';
        if (!is_dir($dir)) {
            wp_mkdir_p($dir);
        }
        return $dir;
    }
    
    /**
     * Get file path for cache key
     */
    private static function path(string $key): string {
        $b = self::base();
        if (empty($b)) {
            return '';
        }
        
        $h = sha1($key);
        $d = $b . '/' . substr($h, 0, 2); // Subfolder by first 2 chars
        if (!is_dir($d)) {
            wp_mkdir_p($d);
            // Create protection files in subdirectory
            self::createProtectionFiles($d);
        }
        return $d . '/' . $h . '.json';
    }
    
    /**
     * Get cached data
     */
    public static function get(string $key) {
        $f = self::path($key);
        if (empty($f) || !is_readable($f)) {
            return null;
        }
        
        $raw = file_get_contents($f);
        if ($raw === false) {
            return null;
        }
        
        $data = json_decode($raw, true);
        if (!is_array($data) || !isset($data['value']) || !isset($data['expires'])) {
            return null;
        }
        
        // Check TTL
        if ($data['expires'] > 0 && time() > $data['expires']) {
            @unlink($f);
            return null;
        }
        
        return $data['value'];
    }
    
    /**
     * Set cached data
     */
    public static function set(string $key, $value, int $ttl = 60): bool {
        $f = self::path($key);
        if (empty($f)) {
            return false;
        }
        
        $tmp = $f . '.tmp';
        
        $data = [
            'value' => $value,
            'expires' => $ttl > 0 ? time() + $ttl : 0,
            'created' => time(),
            'key' => $key // Store key for group clearing
        ];
        
        $json = json_encode($data, JSON_UNESCAPED_SLASHES);
        
        // Atomic write with file locking
        if (file_put_contents($tmp, $json, LOCK_EX) !== false) {
            @rename($tmp, $f);
            @chmod($f, 0640);
            return true;
        }
        
        @unlink($tmp);
        return false;
    }
    
    /**
     * Delete cached data
     */
    public static function delete(string $key): bool {
        $f = self::path($key);
        if (empty($f) || !file_exists($f)) {
            return true;
        }
        return @unlink($f);
    }
    
    /**
     * Increment counter
     */
    public static function increment(string $key, int $value = 1): int {
        $current = self::get($key);
        if ($current === null) {
            $current = 0;
        }
        
        $new = $current + $value;
        self::set($key, $new, 0); // No TTL for counters
        return $new;
    }
    
    /**
     * Clear cache group
     */
    public static function clearGroup(string $group): void {
        $base = self::base();
        if (empty($base) || !is_dir($base)) {
            return;
        }
        
        $it = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($base, \FilesystemIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::CHILD_FIRST
        );
        
        foreach ($it as $file) {
            if ($file->isFile() && substr($file->getFilename(), -5) === '.json') {
                $content = file_get_contents($file->getPathname());
                if ($content !== false) {
                    $data = json_decode($content, true);
                    if (is_array($data) && isset($data['key']) && strpos($data['key'], $group) === 0) {
                        @unlink($file->getPathname());
                    }
                }
            }
        }
    }
    
    /**
     * Clear all cache
     */
    public static function clearAll(): void {
        $base = self::base();
        if (empty($base) || !is_dir($base)) {
            return;
        }
        
        $it = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($base, \FilesystemIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::CHILD_FIRST
        );
        
        foreach ($it as $file) {
            if ($file->isFile() && substr($file->getFilename(), -5) === '.json') {
                @unlink($file->getPathname());
            }
        }
    }
    
    /**
     * Garbage collection
     */
    public static function gc(): void {
        $base = self::base();
        if (empty($base) || !is_dir($base)) {
            return;
        }
        
        $now = time();
        $it = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($base, \FilesystemIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::CHILD_FIRST
        );
        
        foreach ($it as $file) {
            if ($file->isFile() && substr($file->getFilename(), -5) === '.json') {
                $content = file_get_contents($file->getPathname());
                if ($content !== false) {
                    $data = json_decode($content, true);
                    if (is_array($data) && isset($data['expires']) && $data['expires'] > 0 && $now > $data['expires']) {
                        @unlink($file->getPathname());
                    }
                }
            }
        }
    }
    
    /**
     * Create protection files in cache directory
     */
    private static function createProtectionFiles(string $cacheDir): void {
        // Create index.html to prevent directory listing
        $indexFile = $cacheDir . '/index.html';
        if (!file_exists($indexFile)) {
            @file_put_contents($indexFile, '<!-- Directory access denied -->');
        }
        
        // Create .htaccess for Apache protection - DENY ALL ACCESS
        $htaccessFile = $cacheDir . '/.htaccess';
        if (!file_exists($htaccessFile)) {
            $htaccessContent = "<IfModule mod_authz_core.c>\n  Require all denied\n</IfModule>\n<IfModule !mod_authz_core.c>\n  Deny from all\n</IfModule>\n";
            @file_put_contents($htaccessFile, $htaccessContent);
        }
    }
}
