import Foundation
import UIKit

/// Service for caching images to disk for persistent storage across app launches
actor ImageCacheService {
    static let shared = ImageCacheService()

    private let fileManager = FileManager.default
    private let cacheDirectory: URL
    private var memoryCache: [String: UIImage] = [:]
    private let maxMemoryCacheSize = 100  // Max images in memory

    private init() {
        // Use caches directory for image storage
        let cachesPath = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
        cacheDirectory = cachesPath.appendingPathComponent("ImageCache", isDirectory: true)

        // Create directory if needed
        try? fileManager.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
    }

    /// Get cached image for URL (checks memory first, then disk)
    func image(for url: URL) -> UIImage? {
        let key = cacheKey(for: url)

        // Check memory cache first
        if let cached = memoryCache[key] {
            return cached
        }

        // Check disk cache
        let filePath = cacheDirectory.appendingPathComponent(key)
        guard fileManager.fileExists(atPath: filePath.path),
              let data = try? Data(contentsOf: filePath),
              let image = UIImage(data: data) else {
            return nil
        }

        // Add to memory cache
        addToMemoryCache(image, for: key)

        return image
    }

    /// Cache image for URL (saves to both memory and disk)
    func cache(image: UIImage, for url: URL) {
        let key = cacheKey(for: url)

        // Add to memory cache
        addToMemoryCache(image, for: key)

        // Save to disk asynchronously
        let filePath = cacheDirectory.appendingPathComponent(key)
        if let data = image.jpegData(compressionQuality: 0.8) {
            try? data.write(to: filePath)
        }
    }

    /// Generate cache key from URL (uses hash for filename safety)
    private func cacheKey(for url: URL) -> String {
        let hash = url.absoluteString.hashValue
        return "\(abs(hash)).jpg"
    }

    /// Add image to memory cache with LRU eviction
    private func addToMemoryCache(_ image: UIImage, for key: String) {
        if memoryCache.count >= maxMemoryCacheSize {
            // Remove oldest entry (simple approach)
            if let firstKey = memoryCache.keys.first {
                memoryCache.removeValue(forKey: firstKey)
            }
        }
        memoryCache[key] = image
    }

    /// Clear all cached images
    func clearCache() {
        memoryCache.removeAll()
        try? fileManager.removeItem(at: cacheDirectory)
        try? fileManager.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
    }

    /// Get cache size in bytes
    func cacheSize() -> Int64 {
        guard let enumerator = fileManager.enumerator(at: cacheDirectory, includingPropertiesForKeys: [.fileSizeKey]) else {
            return 0
        }

        var totalSize: Int64 = 0
        for case let fileURL as URL in enumerator {
            if let size = try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize {
                totalSize += Int64(size)
            }
        }
        return totalSize
    }
}
