//
//  ImageCache.swift
//  Reflect
//
//  In-memory image cache for thumbnail images to improve scrolling performance.
//

import UIKit
import SwiftUI

/// Thread-safe in-memory image cache
final class ImageCache {
    static let shared = ImageCache()

    private let cache = NSCache<NSString, UIImage>()
    private let queue = DispatchQueue(label: "com.88oakapps.reflect.imagecache", qos: .userInitiated)

    private var memoryWarningToken: NSObjectProtocol?

    private init() {
        // Configure cache limits
        cache.countLimit = 100 // Max 100 images
        cache.totalCostLimit = 50 * 1024 * 1024 // 50 MB max

        // Clear cache on memory warning
        memoryWarningToken = NotificationCenter.default.addObserver(
            forName: UIApplication.didReceiveMemoryWarningNotification,
            object: nil,
            queue: .main
        ) { [weak self] _ in
            self?.clearCache()
        }
    }

    deinit {
        if let token = memoryWarningToken {
            NotificationCenter.default.removeObserver(token)
        }
    }

    // MARK: - Public API

    /// Get image from cache
    func image(forKey key: String) -> UIImage? {
        queue.sync {
            cache.object(forKey: key as NSString)
        }
    }

    /// Store image in cache
    func setImage(_ image: UIImage, forKey key: String) {
        queue.async { [weak self] in
            let cost = Int(image.size.width * image.size.height * 4) // Approximate memory cost
            self?.cache.setObject(image, forKey: key as NSString, cost: cost)
        }
    }

    /// Remove image from cache
    func removeImage(forKey key: String) {
        queue.async { [weak self] in
            self?.cache.removeObject(forKey: key as NSString)
        }
    }

    /// Clear all cached images
    func clearCache() {
        queue.async { [weak self] in
            self?.cache.removeAllObjects()
        }
    }

    // MARK: - Convenience Methods for Photo IDs

    /// Get cached image for photo ID
    func image(forPhotoID id: UUID) -> UIImage? {
        image(forKey: id.uuidString)
    }

    /// Store image for photo ID
    func setImage(_ image: UIImage, forPhotoID id: UUID) {
        setImage(image, forKey: id.uuidString)
    }

    /// Remove cached image for photo ID
    func removeImage(forPhotoID id: UUID) {
        removeImage(forKey: id.uuidString)
    }
}

// MARK: - Cached Photo Loading

extension PhotoManager {
    /// Load thumbnail with caching
    func loadCachedThumbnail(id: UUID) -> UIImage? {
        // Check cache first
        if let cached = ImageCache.shared.image(forPhotoID: id) {
            return cached
        }

        // Load from disk
        guard let image = loadThumbnail(id: id) else {
            return nil
        }

        // Cache for future use
        ImageCache.shared.setImage(image, forPhotoID: id)
        return image
    }

    /// Load full image with caching
    func loadCachedPhoto(id: UUID) -> UIImage? {
        let cacheKey = "\(id.uuidString)-full"

        // Check cache first
        if let cached = ImageCache.shared.image(forKey: cacheKey) {
            return cached
        }

        // Load from disk
        guard let image = loadPhoto(id: id) else {
            return nil
        }

        // Cache for future use
        ImageCache.shared.setImage(image, forKey: cacheKey)
        return image
    }
}

// MARK: - SwiftUI Cached Image View

struct CachedAsyncImage: View {
    let photoID: UUID?
    let useThumbnail: Bool

    @State private var image: UIImage?
    @State private var isLoading = false

    init(photoID: UUID?, useThumbnail: Bool = true) {
        self.photoID = photoID
        self.useThumbnail = useThumbnail
    }

    var body: some View {
        Group {
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
            } else if isLoading {
                ProgressView()
            } else {
                Color.gray.opacity(0.2)
            }
        }
        .onAppear {
            loadImage()
        }
    }

    @MainActor
    private func loadImage() {
        guard let id = photoID else { return }
        isLoading = true

        Task {
            let loadedImage = await Task.detached(priority: .userInitiated) {
                if useThumbnail {
                    return await PhotoManager.shared.loadCachedThumbnail(id: id)
                } else {
                    return await PhotoManager.shared.loadCachedPhoto(id: id)
                }
            }.value

            await MainActor.run {
                self.image = loadedImage
                self.isLoading = false
            }
        }
    }
}
