<?php
class Cache {
    private $cacheDir;
    private $filesDir;
    private $imgDir;
    private $zipDir;
    private $versionDb;
    private $versionPdo = null;
    public function __construct($indexerFilesDir) {
        $this->cacheDir = $indexerFilesDir . '/cache';
        $this->filesDir = $this->cacheDir . '/files';
        $this->imgDir = $this->cacheDir . '/img';
        $this->zipDir = $this->cacheDir . '/zip';
        $this->versionDb = $this->cacheDir . '/version.sqlite';
        if (!is_dir($this->cacheDir)) {
            require_once dirname(__FILE__) . '/Initializer.php';
            $initializer = new Initializer($indexerFilesDir);
            $initializer->initializeCache(false);
        }
        $this->initialize();
    }
    private function initialize() {
        $this->initializeVersionDb();
    }
    private function initializeVersionDb() {
        if (!is_dir($this->cacheDir)) {
            return;
        }
        try {
            $this->versionPdo = new PDO('sqlite:' . $this->versionDb);
            $this->versionPdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->versionPdo->exec("CREATE TABLE IF NOT EXISTS version_info (
                key TEXT PRIMARY KEY,
                value TEXT NOT NULL,
                cached_at INTEGER NOT NULL
            )");
            if (file_exists($this->versionDb)) {
                @chmod($this->versionDb, 0666);
            }
        } catch (Exception $e) {
            $this->versionPdo = null;
        }
    }
    private function generateHash($filePath, $additionalData = '') {
        return md5($filePath . $additionalData . filemtime($filePath));
    }
    public function getFile($sourceFile, $viewType = 'code') {
        $hash = $this->generateHash($sourceFile, $viewType);
        $cachePath = $this->filesDir . '/' . $hash . '.cache';
        if (file_exists($cachePath)) {
            return file_get_contents($cachePath);
        }
        return null;
    }
    public function setFile($sourceFile, $content, $viewType = 'code') {
        if (!is_dir($this->filesDir)) {
            @mkdir($this->filesDir, 0777, true);
        }
        $hash = $this->generateHash($sourceFile, $viewType);
        $cachePath = $this->filesDir . '/' . $hash . '.cache';
        try {
            file_put_contents($cachePath, $content);
            @chmod($cachePath, 0666);
            return $hash;
        } catch (Exception $e) {
            error_log("Cache file write error: " . $e->getMessage());
            return false;
        }
    }
    public function hasValidFile($sourceFile, $viewType = 'code') {
        if (!file_exists($sourceFile)) {
            return false;
        }
        $hash = $this->generateHash($sourceFile, $viewType);
        $cachePath = $this->filesDir . '/' . $hash . '.cache';
        if (!file_exists($cachePath)) {
            return false;
        }
        return filemtime($cachePath) >= filemtime($sourceFile);
    }
    public function getImage($sourceFile, $maxWidth = null, $maxHeight = null) {
        $additionalData = $maxWidth . 'x' . $maxHeight;
        $hash = $this->generateHash($sourceFile, $additionalData);
        $cachePath = $this->imgDir . '/' . $hash . '.cache';
        if (file_exists($cachePath)) {
            return file_get_contents($cachePath);
        }
        return null;
    }
    public function setImage($sourceFile, $imageData, $maxWidth = null, $maxHeight = null) {
        if (!is_dir($this->imgDir)) {
            @mkdir($this->imgDir, 0777, true);
        }
        $additionalData = $maxWidth . 'x' . $maxHeight;
        $hash = $this->generateHash($sourceFile, $additionalData);
        $cachePath = $this->imgDir . '/' . $hash . '.cache';
        try {
            file_put_contents($cachePath, $imageData);
            @chmod($cachePath, 0666);
            return $hash;
        } catch (Exception $e) {
            error_log("Cache image write error: " . $e->getMessage());
            return false;
        }
    }
    public function hasValidImage($sourceFile, $maxWidth = null, $maxHeight = null) {
        if (!file_exists($sourceFile)) {
            return false;
        }
        $additionalData = $maxWidth . 'x' . $maxHeight;
        $hash = $this->generateHash($sourceFile, $additionalData);
        $cachePath = $this->imgDir . '/' . $hash . '.cache';
        if (!file_exists($cachePath)) {
            return false;
        }
        return filemtime($cachePath) >= filemtime($sourceFile);
    }
    public function getImageDataUri($sourceFile, $maxWidth = null, $maxHeight = null, $mimeType = 'image/png') {
        $imageData = $this->getImage($sourceFile, $maxWidth, $maxHeight);
        if ($imageData) {
            return 'data:' . $mimeType . ';base64,' . base64_encode($imageData);
        }
        return null;
    }
    public function setImageDataUri($sourceFile, $imageData, $maxWidth = null, $maxHeight = null, $mimeType = 'image/png') {
        $hash = $this->setImage($sourceFile, $imageData, $maxWidth, $maxHeight);
        if ($hash) {
            return 'data:' . $mimeType . ';base64,' . base64_encode($imageData);
        }
        return null;
    }
    public function createZipTemp($folderName) {
        if (!is_dir($this->zipDir)) {
            @mkdir($this->zipDir, 0777, true);
        }
        $hash = md5($folderName . time() . bin2hex(random_bytes(8)));
        $tempDir = $this->zipDir . '/' . $hash;
        if (!is_dir($tempDir)) {
            @mkdir($tempDir, 0777, true);
            @chmod($tempDir, 0777);
        }
        return [
            'hash' => $hash,
            'path' => $tempDir
        ];
    }
    public function getZipPath($hash) {
        return $this->zipDir . '/' . $hash . '.zip';
    }
    public function hasZip($hash) {
        return file_exists($this->getZipPath($hash));
    }
    public function deleteZipTemp($hash) {
        $tempDir = $this->zipDir . '/' . $hash;
        if (is_dir($tempDir)) {
            $this->deleteDirectory($tempDir);
        }
    }
    public function deleteZip($hash) {
        $zipPath = $this->getZipPath($hash);
        if (file_exists($zipPath)) {
            unlink($zipPath);
        }
    }
    private function deleteDirectory($dir) {
        if (!is_dir($dir)) return;
        $files = glob($dir . '/*');
        foreach ($files as $file) {
            if (is_dir($file)) {
                $this->deleteDirectory($file);
            } else {
                unlink($file);
            }
        }
        rmdir($dir);
    }
    public function getVersionInfo() {
        if (!$this->versionPdo) {
            return null;
        }
        try {
            $stmt = $this->versionPdo->prepare("SELECT value, cached_at FROM version_info WHERE key = 'remote_version_info'");
            $stmt->execute();
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($result) {
                if (time() - $result['cached_at'] < 7200) {
                    return json_decode($result['value'], true);
                }
            }
            return null;
        } catch (Exception $e) {
            error_log("Version info get error: " . $e->getMessage());
            return null;
        }
    }
    public function setVersionInfo($versionData) {
        if (!$this->versionPdo) {
            return false;
        }
        try {
            $stmt = $this->versionPdo->prepare("INSERT OR REPLACE INTO version_info (key, value, cached_at) VALUES (?, ?, ?)");
            $stmt->execute([
                'remote_version_info',
                json_encode($versionData),
                time()
            ]);
            return true;
        } catch (Exception $e) {
            error_log("Version info set error: " . $e->getMessage());
            return false;
        }
    }
    public function getStatistics() {
        $stats = [
            'files' => [
                'count' => 0,
                'size' => 0
            ],
            'images' => [
                'count' => 0,
                'size' => 0
            ],
            'zips' => [
                'count' => 0,
                'size' => 0
            ],
            'total_size' => 0
        ];
        $files = glob($this->filesDir . '/*.cache');
        $stats['files']['count'] = count($files);
        foreach ($files as $file) {
            $stats['files']['size'] += filesize($file);
        }
        $images = glob($this->imgDir . '/*.cache');
        $stats['images']['count'] = count($images);
        foreach ($images as $image) {
            $stats['images']['size'] += filesize($image);
        }
        $zips = glob($this->zipDir . '/*.zip');
        $stats['zips']['count'] = count($zips);
        foreach ($zips as $zip) {
            $stats['zips']['size'] += filesize($zip);
        }
        $tempDirs = glob($this->zipDir . '/*', GLOB_ONLYDIR);
        $stats['zips']['temp_dirs'] = count($tempDirs);
        $stats['total_size'] = $stats['files']['size'] + $stats['images']['size'] + $stats['zips']['size'];
        return $stats;
    }
    public function clearFiles() {
        $deleted = 0;
        $files = glob($this->filesDir . '/*.cache');
        foreach ($files as $file) {
            if (unlink($file)) {
                $deleted++;
            }
        }
        return $deleted;
    }
    public function clearImages() {
        $deleted = 0;
        $images = glob($this->imgDir . '/*.cache');
        foreach ($images as $image) {
            if (unlink($image)) {
                $deleted++;
            }
        }
        return $deleted;
    }
    public function clearZips() {
        $deleted = 0;
        $zips = glob($this->zipDir . '/*.zip');
        foreach ($zips as $zip) {
            if (unlink($zip)) {
                $deleted++;
            }
        }
        $tempDirs = glob($this->zipDir . '/*', GLOB_ONLYDIR);
        foreach ($tempDirs as $dir) {
            $this->deleteDirectory($dir);
            $deleted++;
        }
        return $deleted;
    }
    public function clearVersionDb() {
        $deleted = 0;
        if (file_exists($this->versionDb)) {
            if (@unlink($this->versionDb)) {
                $deleted = 1;
                $this->versionPdo = null; 
            }
        }
        return $deleted;
    }
    public function clearAll() {
        $filesDeleted = $this->clearFiles();
        $imagesDeleted = $this->clearImages();
        $zipsDeleted = $this->clearZips();
        $versionDbDeleted = $this->clearVersionDb();
        return [
            'files' => $filesDeleted,
            'images' => $imagesDeleted,
            'zips' => $zipsDeleted,
            'version_db' => $versionDbDeleted,
            'total' => $filesDeleted + $imagesDeleted + $zipsDeleted + $versionDbDeleted
        ];
    }
    public function getPaths() {
        return [
            'base' => $this->cacheDir,
            'files' => $this->filesDir,
            'images' => $this->imgDir,
            'zips' => $this->zipDir,
            'version_db' => $this->versionDb
        ];
    }
    public function formatBytes($bytes) {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
            $bytes /= 1024;
        }
        return round($bytes, 2) . ' ' . $units[$i];
    }
}
if (!defined('INDEXER_FILES_ROOT_DIR')) {
    define('INDEXER_FILES_ROOT_DIR', dirname(dirname(__FILE__))); 
}
if (php_sapi_name() === 'cli') {
    if ($argc < 2) {
        displayHelp();
        exit(1);
    }
    $command = strtolower($argv[1]);
    $cache = null;
    try {
        $cache = new Cache(INDEXER_FILES_ROOT_DIR);
        switch ($command) {
            case 'help':
                displayHelp();
                break;
            case 'clear-all-cache':
                $results = $cache->clearAll();
                echo "   Successfully cleared all caches:\n";
                echo "   - Files cache items cleared: " . $results['files'] . "\n";
                echo "   - Image cache items cleared: " . $results['images'] . "\n";
                echo "   - Zip cache/temp items cleared: " . $results['zips'] . "\n";
                echo "   - Version DB file cleared: " . ($results['version_db'] ? '1' : '0') . "\n";
                echo "   Total items removed: " . $results['total'] . "\n";
                break;
            case 'clear-files-cache':
                $count = $cache->clearFiles();
                echo " Files cache cleared: $count file(s) removed.\n";
                break;
            case 'clear-img-cache':
                $count = $cache->clearImages();
                echo " Image cache cleared: $count image file(s) removed.\n";
                break;
            case 'clear-version-cache':
                $count = $cache->clearVersionDb();
                if ($count > 0) {
                    echo " Version DB cache cleared: version.sqlite file removed.\n";
                } else {
                    echo " Version DB cache file (version.sqlite) was not found or could not be removed.\n";
                }
                break;
            case 'stats':
                $stats = $cache->getStatistics();
                echo "\n Cache Statistics:\n";
                echo "----------------------------------------\n";
                echo "Total Size: " . $cache->formatBytes($stats['total_size']) . "\n";
                echo "----------------------------------------\n";
                echo "Files Cache:\n";
                echo "  Items: " . number_format($stats['files']['count']) . "\n";
                echo "  Size: " . $cache->formatBytes($stats['files']['size']) . "\n";
                echo "Image Cache:\n";
                echo "  Items: " . number_format($stats['images']['count']) . "\n";
                echo "  Size: " . $cache->formatBytes($stats['images']['size']) . "\n";
                echo "Zip Cache:\n";
                echo "  Zips: " . number_format($stats['zips']['count']) . " files\n";
                echo "  Temp Dirs: " . number_format($stats['zips']['temp_dirs']) . " directories\n";
                echo "  Size: " . $cache->formatBytes($stats['zips']['size']) . "\n";
                echo "----------------------------------------\n";
                break;
            case 'show-paths':
                $paths = $cache->getPaths();
                echo "\n Cache Directory Paths:\n";
                echo "--------------------------------------------------------\n";
                echo "Base Cache Dir:  " . $paths['base'] . "\n";
                echo "Files Cache Dir: " . $paths['files'] . "\n";
                echo "Image Cache Dir: " . $paths['images'] . "\n";
                echo "Zip Cache Dir:   " . $paths['zips'] . "\n";
                echo "Version DB File: " . $paths['version_db'] . "\n";
                echo "--------------------------------------------------------\n";
                break;
            default:
                echo " Unknown command: '$command'.\n";
                displayHelp();
                exit(1);
        }
    } catch (Exception $e) {
        fwrite(STDERR, " An error occurred: " . $e->getMessage() . "\n");
        exit(1);
    }
}
function displayHelp() {
    global $argv;
    $scriptName = basename($argv[0]);
    echo "\n";
    echo "Available Commands:\n";
    echo "  stats                : Shows current cache statistics (size and item count).\n";
    echo "  show-paths           : Shows the configured cache directory paths.\n";
    echo "  clear-all-cache      : Clears all file, image, zip, and version database caches.\n";
    echo "  clear-files-cache    : Clears only the file content caches.\n";
    echo "  clear-img-cache      : Clears only the image/thumbnail caches.\n";
    echo "  clear-version-cache  : Clears only the version info database (version.sqlite).\n";
    echo "\n";
}
?>