//
//  UserDefaultsExt.swift
//  PaiaiDataKit
//
//  Created by FFIB on 2017/9/22.
//  Copyright © 2017年 FFIB. All rights reserved.
//

import Foundation

public protocol BoolUserDefaultable {
    associatedtype BoolDefaultKey: RawRepresentable
}

extension BoolUserDefaultable where BoolDefaultKey.RawValue == String {
    public static func set(_ value: Bool, forKey key: BoolDefaultKey) {
        let key = key.rawValue
        UserDefaults.standard.set(value, forKey: key)
    }
    public static func bool(forKey key: BoolDefaultKey) -> Bool {
        let key = key.rawValue
        return UserDefaults.standard.bool(forKey: key)
    }

}

public protocol StringUserDefaultable {
    associatedtype StringDefaultKey: RawRepresentable
}

extension StringUserDefaultable where StringDefaultKey.RawValue == String {
    public static func set(_ value: String, forKey key: StringDefaultKey) {
        let key = key.rawValue
        UserDefaults.standard.set(value, forKey: key)
    }
    public static func string(forKey key: StringDefaultKey) -> String {
        let key = key.rawValue
        return UserDefaults.standard.string(forKey: key) ?? ""
    }
}

public protocol DoubleUserDefaultable {
    associatedtype DoubleDefaultKey: RawRepresentable
}

extension DoubleUserDefaultable where DoubleDefaultKey.RawValue == String {
    public static func set(_ value: Double, forKey key: DoubleDefaultKey) {
        let key = key.rawValue
        UserDefaults.standard.set(value, forKey: key)
    }
    public static func double(forKey key: DoubleDefaultKey) -> Double {
        let key = key.rawValue
        return UserDefaults.standard.double(forKey: key)
    }
}

public protocol IntUserDefaultable {
    associatedtype IntDefaultKey: RawRepresentable
}

extension IntUserDefaultable where IntDefaultKey.RawValue == String {
    public static func set(_ value: Int, forKey key: IntDefaultKey) {
        let key = key.rawValue
        UserDefaults.standard.set(value, forKey: key)
    }
    public static func int(forKey key: IntDefaultKey) -> Int {
        let key = key.rawValue
        return UserDefaults.standard.integer(forKey: key)
    }
}

public protocol DataUserDefaultable {
    associatedtype DataDefaultKey: RawRepresentable
}

extension DataUserDefaultable where DataDefaultKey.RawValue == String {
    public static func set(_ value: Data, forKey key: DataDefaultKey) {
        let key = key.rawValue
        UserDefaults.standard.set(value, forKey: key)
    }
    public static func data(forKey key: DataDefaultKey) -> Data {
        let key = key.rawValue
        return UserDefaults.standard.data(forKey: key) ?? Data()
    }
}

public protocol ArrayUserDefaultCodable {
    init(value: [String: AnyObject])
    func toDictionary() -> [String: AnyObject]
}

public protocol ArrayUserDefaultable {
    associatedtype ArrayDefaultKey: RawRepresentable
    associatedtype Item: ArrayUserDefaultCodable
}

extension ArrayUserDefaultable where ArrayDefaultKey.RawValue == String {
    public static func set(_ value: [Item], forKey key: ArrayDefaultKey) {
        let key = key.rawValue
        UserDefaults.standard.set(value.flatMap { $0.toDictionary() }, forKey: key)
    }
    public static func array(forKey key: ArrayDefaultKey) -> [Item] {
        let key = key.rawValue
        guard let value = UserDefaults.standard.array(forKey: key) as? [[String: AnyObject]] else {
            return []
        }
        let items = value.compactMap { Item.init(value: $0) }
        return items
    }
}

public protocol DictionaryUserDefaultable {
    associatedtype DictionaryDefaultKey: RawRepresentable
}

extension DictionaryUserDefaultable where DictionaryDefaultKey.RawValue == String {
    public static func set(_ value: [String: Any], forKey key: DictionaryDefaultKey) {
        let key = key.rawValue
        UserDefaults.standard.set(value, forKey: key)
    }
    public static func dictionary(forKey key: DictionaryDefaultKey) -> [String: Any] {
        let key = key.rawValue
        return UserDefaults.standard.dictionary(forKey: key) ?? [String: Any]()
    }
}