<?php
class Database {
    public $pdo = null;
    private $dbPath;
    private $configFile;
    private $extensionMapFile;
    private $iconsFile;
    public function __construct($indexerFilesDir, $baseDir = null) {
        $dbDir = $indexerFilesDir . '/db';
        $this->dbPath = $dbDir . '/indexer.sqlite';
        $this->configFile = $indexerFilesDir . '/config.json';
        $this->extensionMapFile = $indexerFilesDir . '/local_api/extensionMap.json';
        $this->iconsFile = $indexerFilesDir . '/local_api/icons.json';
        if (!file_exists($this->dbPath)) {
            require_once dirname(__FILE__) . '/Initializer.php';
            $initializer = new Initializer($indexerFilesDir, $baseDir);
            $initializer->initializeDatabase(false);
        }
        $this->initialize();
    }
    private function initialize() {
        try {
            $this->pdo = new PDO('sqlite:' . $this->dbPath);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->createTables();
            $this->syncSystemFiles();
        } catch (Exception $e) {
            error_log("Database initialization error: " . $e->getMessage());
            throw $e;
        }
    }
    private function createTables() {
        $this->pdo->exec("CREATE TABLE IF NOT EXISTS system_config (
            key TEXT PRIMARY KEY,
            value TEXT NOT NULL,
            last_updated INTEGER NOT NULL
        )");
        $this->pdo->exec("CREATE TABLE IF NOT EXISTS extension_mappings (
            extension TEXT PRIMARY KEY,
            indexing_setting TEXT,
            viewing_setting TEXT,
            last_updated INTEGER NOT NULL
        )");
        $this->pdo->exec("CREATE TABLE IF NOT EXISTS icon_mappings (
            identifier TEXT PRIMARY KEY,
            icon_filename TEXT NOT NULL,
            last_updated INTEGER NOT NULL
        )");
        $this->pdo->exec("CREATE TABLE IF NOT EXISTS file_metadata (
            path TEXT PRIMARY KEY,
            filename TEXT NOT NULL,
            extension TEXT,
            size INTEGER NOT NULL,
            modified INTEGER NOT NULL,
            is_directory INTEGER NOT NULL,
            parent_path TEXT,
            indexed_at INTEGER NOT NULL,
            last_verified INTEGER NOT NULL
        )");
        $this->pdo->exec("CREATE INDEX IF NOT EXISTS idx_file_parent ON file_metadata(parent_path)");
        $this->pdo->exec("CREATE INDEX IF NOT EXISTS idx_file_extension ON file_metadata(extension)");
        $this->pdo->exec("CREATE INDEX IF NOT EXISTS idx_file_modified ON file_metadata(modified)");
        $this->pdo->exec("CREATE INDEX IF NOT EXISTS idx_file_directory ON file_metadata(is_directory)");
    }
    public function syncSystemFiles() {
        static $synced = false;
        if ($synced) {
            return;
        }
        $synced = true;
        if (file_exists($this->configFile)) {
            $configModified = filemtime($this->configFile);
            $stmt = $this->pdo->prepare("SELECT last_updated FROM system_config WHERE key = 'config_timestamp'");
            $stmt->execute();
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$result || $result['last_updated'] < $configModified) {
                $configData = json_decode(file_get_contents($this->configFile), true);
                if ($configData) {
                    $this->updateSystemConfig($configData);
                }
            }
        }
        if (file_exists($this->extensionMapFile)) {
            $mapModified = filemtime($this->extensionMapFile);
            $stmt = $this->pdo->prepare("SELECT last_updated FROM system_config WHERE key = 'extension_map_timestamp'");
            $stmt->execute();
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$result || $result['last_updated'] < $mapModified) {
                $mapData = json_decode(file_get_contents($this->extensionMapFile), true);
                if ($mapData) {
                    $this->updateExtensionMappings($mapData);
                }
            }
        }
        if (file_exists($this->iconsFile)) {
            $iconsModified = filemtime($this->iconsFile);
            $stmt = $this->pdo->prepare("SELECT last_updated FROM system_config WHERE key = 'icons_timestamp'");
            $stmt->execute();
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$result || $result['last_updated'] < $iconsModified) {
                $iconsData = json_decode(file_get_contents($this->iconsFile), true);
                if ($iconsData) {
                    $this->updateIconMappings($iconsData);
                }
            }
        }
    }
    private function updateSystemConfig($configData) {
        $timestamp = time();
        $this->pdo->beginTransaction();
        try {
            $stmt = $this->pdo->prepare("INSERT OR REPLACE INTO system_config (key, value, last_updated) VALUES (?, ?, ?)");
            $stmt->execute(['config_data', json_encode($configData), $timestamp]);
            $stmt->execute(['config_timestamp', $timestamp, $timestamp]);
            if (isset($configData['version'])) {
                $stmt->execute(['version', $configData['version'], $timestamp]);
            }
            if (isset($configData['main'])) {
                foreach ($configData['main'] as $key => $value) {
                    $stmt->execute(['main_' . $key, json_encode($value), $timestamp]);
                }
            }
            $this->pdo->commit();
        } catch (Exception $e) {
            $this->pdo->rollBack();
            error_log("Config update error: " . $e->getMessage());
        }
    }
    private function updateExtensionMappings($mapData) {
        $timestamp = time();
        $this->pdo->beginTransaction();
        try {
            $this->pdo->exec("DELETE FROM extension_mappings");
            $stmt = $this->pdo->prepare("INSERT INTO extension_mappings (extension, indexing_setting, viewing_setting, last_updated) VALUES (?, ?, ?, ?)");
            if (isset($mapData['indexing'])) {
                foreach ($mapData['indexing'] as $ext => $setting) {
                    $viewingSetting = isset($mapData['viewing'][$ext]) ? $mapData['viewing'][$ext] : null;
                    $stmt->execute([$ext, $setting, $viewingSetting, $timestamp]);
                }
            }
            if (isset($mapData['viewing'])) {
                foreach ($mapData['viewing'] as $ext => $setting) {
                    if (!isset($mapData['indexing'][$ext])) {
                        $stmt->execute([$ext, null, $setting, $timestamp]);
                    }
                }
            }
            $stmt = $this->pdo->prepare("INSERT OR REPLACE INTO system_config (key, value, last_updated) VALUES (?, ?, ?)");
            $stmt->execute(['extension_map_timestamp', $timestamp, $timestamp]);
            $this->pdo->commit();
        } catch (Exception $e) {
            $this->pdo->rollBack();
            error_log("Extension map update error: " . $e->getMessage());
        }
    }
    private function updateIconMappings($iconsData) {
        $timestamp = time();
        $this->pdo->beginTransaction();
        try {
            $this->pdo->exec("DELETE FROM icon_mappings");
            $stmt = $this->pdo->prepare("INSERT INTO icon_mappings (identifier, icon_filename, last_updated) VALUES (?, ?, ?)");
            foreach ($iconsData as $identifier => $iconFile) {
                $stmt->execute([$identifier, $iconFile, $timestamp]);
            }
            $stmt = $this->pdo->prepare("INSERT OR REPLACE INTO system_config (key, value, last_updated) VALUES (?, ?, ?)");
            $stmt->execute(['icons_timestamp', $timestamp, $timestamp]);
            $this->pdo->commit();
        } catch (Exception $e) {
            $this->pdo->rollBack();
            error_log("Icons update error: " . $e->getMessage());
        }
    }
    public function getConfig($key = null) {
        try {
            if ($key === null) {
                $stmt = $this->pdo->prepare("SELECT value FROM system_config WHERE key = 'config_data'");
                $stmt->execute();
                $result = $stmt->fetch(PDO::FETCH_ASSOC);
                return $result ? json_decode($result['value'], true) : [];
            } else {
                $stmt = $this->pdo->prepare("SELECT value FROM system_config WHERE key = ?");
                $stmt->execute([$key]);
                $result = $stmt->fetch(PDO::FETCH_ASSOC);
                return $result ? json_decode($result['value'], true) : null;
            }
        } catch (Exception $e) {
            error_log("Config get error: " . $e->getMessage());
            return null;
        }
    }
    public function getExtensionSetting($extension, $type = 'indexing') {
        try {
            $stmt = $this->pdo->prepare("SELECT indexing_setting, viewing_setting FROM extension_mappings WHERE extension = ?");
            $stmt->execute([strtolower($extension)]);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($result) {
                return $type === 'indexing' ? $result['indexing_setting'] : $result['viewing_setting'];
            }
            return null;
        } catch (Exception $e) {
            error_log("Extension setting get error: " . $e->getMessage());
            return null;
        }
    }
    public function getIconMapping($identifier) {
        try {
            $stmt = $this->pdo->prepare("SELECT icon_filename FROM icon_mappings WHERE identifier = ?");
            $stmt->execute([strtolower($identifier)]);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            return $result ? $result['icon_filename'] : null;
        } catch (Exception $e) {
            error_log("Icon mapping get error: " . $e->getMessage());
            return null;
        }
    }
    public function indexPath($path, $filename, $extension, $size, $modified, $isDirectory, $parentPath = null) {
        try {
            $timestamp = time();
            $stmt = $this->pdo->prepare("INSERT OR REPLACE INTO file_metadata 
                (path, filename, extension, size, modified, is_directory, parent_path, indexed_at, last_verified) 
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
            $stmt->execute([
                $path,
                $filename,
                $extension ? strtolower($extension) : null,
                $size,
                $modified,
                $isDirectory ? 1 : 0,
                $parentPath,
                $timestamp,
                $timestamp
            ]);
            return true;
        } catch (Exception $e) {
            error_log("Index path error: " . $e->getMessage());
            return false;
        }
    }
    public function getFileMetadata($path) {
        try {
            $stmt = $this->pdo->prepare("SELECT * FROM file_metadata WHERE path = ?");
            $stmt->execute([$path]);
            return $stmt->fetch(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log("Get metadata error: " . $e->getMessage());
            return null;
        }
    }
    public function getDirectoryContents($parentPath) {
        try {
            if ($parentPath === null || $parentPath === '' || $parentPath === 'ROOT_DIR') {
                $stmt = $this->pdo->prepare("SELECT * FROM file_metadata WHERE parent_path IS NULL OR parent_path = '' OR parent_path = 'ROOT_DIR' ORDER BY is_directory DESC, filename ASC");
                $stmt->execute();
            } else {
                $stmt = $this->pdo->prepare("SELECT * FROM file_metadata WHERE parent_path = ? ORDER BY is_directory DESC, filename ASC");
                $stmt->execute([$parentPath]);
            }
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log("Get directory contents error: " . $e->getMessage());
            return [];
        }
    }
    public function needsReindex($path, $currentModified) {
        try {
            $stmt = $this->pdo->prepare("SELECT modified FROM file_metadata WHERE path = ?");
            $stmt->execute([$path]);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$result) {
                return true;
            }
            return $result['modified'] < $currentModified;
        } catch (Exception $e) {
            return true;
        }
    }
    public function cleanupDeletedPaths($basePath, $existingPaths) {
        try {
            $this->pdo->beginTransaction();
            $stmt = $this->pdo->prepare("SELECT path FROM file_metadata WHERE path = ? OR path LIKE ?");
            $stmt->execute([$basePath, $basePath . '/%']);
            $indexedPaths = $stmt->fetchAll(PDO::FETCH_COLUMN);
            $deletedPaths = array_diff($indexedPaths, $existingPaths);
            if (!empty($deletedPaths)) {
                $placeholders = implode(',', array_fill(0, count($deletedPaths), '?'));
                $stmt = $this->pdo->prepare("DELETE FROM file_metadata WHERE path IN ($placeholders)");
                $stmt->execute(array_values($deletedPaths));
            }
            $this->pdo->commit();
            return count($deletedPaths);
        } catch (Exception $e) {
            $this->pdo->rollBack();
            error_log("Cleanup error: " . $e->getMessage());
            return 0;
        }
    }
    public function getStatistics() {
        try {
            $stats = [];
            $stmt = $this->pdo->query("SELECT COUNT(*) as count FROM file_metadata WHERE is_directory = 0");
            $stats['total_files'] = $stmt->fetch(PDO::FETCH_ASSOC)['count'];
            $stmt = $this->pdo->query("SELECT COUNT(*) as count FROM file_metadata WHERE is_directory = 1");
            $stats['total_directories'] = $stmt->fetch(PDO::FETCH_ASSOC)['count'];
            $stmt = $this->pdo->query("SELECT SUM(size) as total FROM file_metadata WHERE is_directory = 0");
            $stats['total_size'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'] ?: 0;
            if (file_exists($this->dbPath)) {
                $stats['database_size'] = filesize($this->dbPath);
            }
            return $stats;
        } catch (Exception $e) {
            error_log("Statistics error: " . $e->getMessage());
            return [];
        }
    }
    public function optimize() {
        try {
            $this->pdo->exec("VACUUM");
            $this->pdo->exec("ANALYZE");
            return true;
        } catch (Exception $e) {
            error_log("Optimize error: " . $e->getMessage());
            return false;
        }
    }
}
?>