//
//  ResourcePolicyManager.swift
//  SBrowser
//
//  Created by James Magahern on 7/22/20.
//

import Foundation

class ResourcePolicyManager: NSObject, SBRResourceOriginPolicyDataSource
{
    static let AllowedOriginsDefaultsKey = "allowedOrigins"
    static let OriginPoliciesDefaultsKey = "originPolicies"
    
    private static func stringSetForKey(_ key: String) -> Set<String> {
        if let set = UserDefaults.standard.array(forKey: key) as? [String] {
            return Set<String>(set)
        }

        return Set<String>()
    }
    
    private static func saveStringSet(_ set: Set<String>, forKey key: String) {
        UserDefaults.standard.set(Array(set), forKey: key)
    }
    
    private var allowedOriginSet: Set<String> = stringSetForKey(AllowedOriginsDefaultsKey) {
        didSet { Self.saveStringSet(allowedOriginSet, forKey: Self.AllowedOriginsDefaultsKey) }
    }
    
    func allowedOriginsForScriptResources() -> Set<String> { allowedOriginSet }
    
    func scriptPolicyTypeByOrigin() -> [String : NSNumber] {
        let types = scriptPolicies.mapValues { NSNumber(integerLiteral: $0.rawValue) }
        return types
    }
    
    private lazy var scriptPolicies: Dictionary<String, ScriptPolicy.PolicyType> = {
        if let existingDict = UserDefaults.standard.dictionary(forKey: Self.OriginPoliciesDefaultsKey) as? Dictionary<String, Int> {
            return existingDict.mapValues { ScriptPolicy.PolicyType(rawValue: $0)! }
        }
        
        return Dictionary<String, ScriptPolicy.PolicyType>()
    }() {
        didSet {
            let encodableDictionary = scriptPolicies.mapValues { $0.rawValue }
            UserDefaults.standard.set(encodableDictionary, forKey: Self.OriginPoliciesDefaultsKey)
        }
    }
    
    func allowOriginToLoadScriptResources(_ origin: String) {
        allowedOriginSet.formUnion([ origin ])
    }
    
    func disallowOriginToLoadScriptResources(_ origin: String) {
        allowedOriginSet.remove(origin)
    }
    
    func scriptPolicy(forOrigin origin: String) -> ScriptPolicy {
        if let policyType = scriptPolicies[origin] {
            return ScriptPolicy(securityOrigin: origin, policyType: policyType)
        }
        
        return ScriptPolicy(securityOrigin: origin, policyType: .alpha)
    }
    
    func setScriptPolicyType(_ policyType: ScriptPolicy.PolicyType, forOrigin origin: String) {
        scriptPolicies[origin] = policyType
    }
}
