import 'dart:io'; import 'package:http/http.dart' as http; import 'package:path_provider/path_provider.dart'; import 'package:stadtbote/tools/util.dart'; class PdfService { static final PdfService _instance = PdfService._internal(); factory PdfService() => _instance; PdfService._internal(); static const String _cacheSubDir = 'pdf_cache'; /// Generates a unique filename from URL using hash String _getFilenameFromUrl(String url) { final hash = Util.fastHash(url); return '${hash.toRadixString(16)}.pdf'; } /// Gets the cache directory for PDFs Future _getCacheDirectory() async { final appDir = await getApplicationDocumentsDirectory(); final cacheDir = Directory('${appDir.path}/$_cacheSubDir'); if (!await cacheDir.exists()) { await cacheDir.create(recursive: true); } return cacheDir; } /// Checks if PDF is already cached and returns the file if it exists Future getCachedPdf(String url) async { try { final cacheDir = await _getCacheDirectory(); final filename = _getFilenameFromUrl(url); final file = File('${cacheDir.path}/$filename'); if (await file.exists()) { Util.logDebug('PDF found in cache: $filename'); return file; } return null; } catch (e) { Util.logException('Error checking PDF cache: $e'); return null; } } /// Downloads PDF from URL and saves it to cache Future downloadAndCachePdf(String url) async { Util.logInfo('Downloading PDF from: $url'); final response = await http.get(Uri.parse(url)); if (response.statusCode != 200) { throw Exception('Failed to download PDF: HTTP ${response.statusCode}'); } final cacheDir = await _getCacheDirectory(); final filename = _getFilenameFromUrl(url); final file = File('${cacheDir.path}/$filename'); await file.writeAsBytes(response.bodyBytes); Util.logInfo('PDF cached successfully: $filename'); return file; } /// Gets PDF from cache or downloads it if not cached Future getPdf(String url) async { final cachedFile = await getCachedPdf(url); if (cachedFile != null) { return cachedFile; } return await downloadAndCachePdf(url); } /// Clears all cached PDFs Future clearCache() async { try { final cacheDir = await _getCacheDirectory(); if (await cacheDir.exists()) { await cacheDir.delete(recursive: true); Util.logInfo('PDF cache cleared'); } } catch (e) { Util.logException('Error clearing PDF cache: $e'); } } /// Gets the total size of cached PDFs in bytes Future getCacheSize() async { try { final cacheDir = await _getCacheDirectory(); if (!await cacheDir.exists()) { return 0; } int totalSize = 0; await for (final entity in cacheDir.list()) { if (entity is File) { totalSize += await entity.length(); } } return totalSize; } catch (e) { Util.logException('Error calculating cache size: $e'); return 0; } } /// Validates if URL is a valid PDF URL bool isValidPdfUrl(String url) { try { final uri = Uri.parse(url); return uri.scheme == 'https' || uri.scheme == 'http'; } catch (e) { return false; } } }