//
//  MemoryCache.swift
//  Tusker
//
//  Created by Shadowfacts on 1/18/21.
//  Copyright © 2021 Shadowfacts. All rights reserved.
//

import Foundation

class MemoryCache<T> {
 
    private let cache = NSCache<NSString, Entry>()
    private let defaultExpiry: CacheExpiry
    
    init(defaultExpiry: CacheExpiry) {
        self.defaultExpiry = defaultExpiry
    }
    
    
    func setObject(_ object: T, forKey key: String) {
        let entry = Entry(expiresAt: defaultExpiry.date, object: object)
        cache.setObject(entry, forKey: key as NSString)
    }
    
    func removeObject(forKey key: String) {
        cache.removeObject(forKey: key as NSString)
    }
    
    func existsObject(forKey key: String) -> Bool {
        return cache.object(forKey: key as NSString) != nil
    }
    
    func object(forKey key: String) throws -> T {
        guard let entry = cache.object(forKey: key as NSString) else {
            throw Error.notFound
        }
        
        guard entry.expiresAt.timeIntervalSinceNow >= 0 else {
            cache.removeObject(forKey: key as NSString)
            throw Error.expired
        }
        
        return entry.object
    }
    
    func removeAll() {
        cache.removeAllObjects()
    }
}

extension MemoryCache {
    enum Error: Swift.Error {
        case notFound
        case expired
    }
}

extension MemoryCache {
    class Entry {
        let expiresAt: Date
        let object: T
        
        init(expiresAt: Date, object: T) {
            self.expiresAt = expiresAt
            self.object = object
        }
    }
}
