//
/*
 * Copyright (c) 2021 BWI GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Foundation

let configKey = "com.apple.configuration.managed"

extension UserDefaults
{
    @objc dynamic var appConfigData: Dictionary<String, Any>?
    {
        get {
            return dictionary(forKey: configKey)
        }
        set {
            set(newValue, forKey: configKey)
        }
    }
}

@objcMembers class AppConfigService : NSObject {
    static let shared = AppConfigService()
    
    private let serverUrlKey = "home_server_url"
    private let contentScannerKey = "contentScanner"
    private let pusherUrlKey = "pusherUrl"
    private let permalinkUrlKey = "permalinkUrl"

    private let savedConfig = "savedAppConfig"
    
    var appConfig = AppConfig()
    
    var completion: ((Bool) -> Void)?
    
    var configObserver: NSKeyValueObservation!
    
    var session: MXSession?
    
    var isAppConfig: Bool
    
    private func loadAppConfig() {
        isAppConfig = false
        do {
            if let dataIn = UserDefaults.standard.value(forKey: savedConfig) as? Data {
                appConfig = try JSONDecoder().decode(AppConfig.self, from: dataIn)
                isAppConfig = true
            }
        } catch {
            
        }
    }
    
    private func saveAppConfig() {
        do {
            let dataOut = try JSONEncoder().encode(appConfig)
            UserDefaults.standard.setValue(dataOut, forKey: savedConfig)
        } catch {
            
        }
    }
    
    private func checkUrlSavety(_ serverUrl: String) -> Bool {
        if BWIBuildSettings.shared.bwiEnableLoginProtection {
            let protectionService = LoginProtectionService()
            protectionService.hashes = BWIBuildSettings.shared.bwiHashes
            
            return protectionService.isValid(serverUrl)
        } else {
            return true
        }
    }
    
    override init() {
        isAppConfig = false
        super.init()
        self.loadAppConfig()
    }
    
    func registerForAppConfig() {
        
        NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: OperationQueue.main) { [self] (note) in
            handleAppConfig()
        }
    }
    
    func handleAppConfig() {
        if let dict = UserDefaults.standard.dictionary(forKey: configKey) {
            var config = AppConfig()
            
            if let serverUrl = dict[serverUrlKey] as? String {
                if serverUrl.count == 0 {
                    config.serverUrl = nil
                } else if checkUrlSavety(serverUrl) {
                    config.serverUrl = serverUrl
                }
            }
            if let contentScannerUrl = dict[contentScannerKey] as? String {
                if checkUrlSavety(contentScannerUrl) {
                    config.contentScannerUrl = contentScannerUrl
                }
            }
            if let pusherUrl = dict[pusherUrlKey] as? String {
                if checkUrlSavety(pusherUrl) {
                    config.pusherUrl = pusherUrl
                }
            }
            if let permalinkUrl = dict[permalinkUrlKey] as? String {
                if checkUrlSavety(permalinkUrl) {
                    config.permalinkUrl = permalinkUrl
                }
            }
            
            // app config needs at least a valid server url
            isAppConfig = (config.serverUrl != nil)
            
            if config != appConfig {
                appConfig = config
                self.saveAppConfig()
                if let completion = completion {
                    completion(true)
                }
            }
            
            UserDefaults.standard.removeObject(forKey: configKey)
        }
    }
    
    func resetConfig() {
        appConfig = AppConfig()
        self.saveAppConfig()
    }
    
    func serverUrl()  -> String {
        if let url = appConfig.serverUrl {
            return url
        } else if let url = ServerURLHelper.shared.serverUrl() {
            return url
        } else if let session = session, let restClient = session.matrixRestClient {
            return restClient.homeserver
        } else {
            return BWIBuildSettings.shared.serverConfigDefaultHomeserverUrlString
        }
    }
    
    func pusherUrl()  -> String {
        if let url = appConfig.pusherUrl {
            return url
        } else {
            return BWIBuildSettings.shared.serverConfigSygnalAPIUrlString
        }
    }
    
    func permalinkUrl() -> String? {
        if let url = appConfig.permalinkUrl {
            return "https://" + url
        }  else if let url = ServerURLHelper.shared.httpsPermalink() {
            return url
        } else {
            return BWIBuildSettings.shared.clientPermalinkBaseUrl
        }
    }
}
