//
//  CredentialDatabase.swift
//  flutter_inappwebview
//
//  Created by Lorenzo Pichilli on 29/10/2019.
//

import Foundation

public class CredentialDatabase: ChannelDelegate {
    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database"
    static let credentialStore = URLCredentialStorage.shared

    private var plugin: SwiftFlutterPlugin?

    init(plugin: SwiftFlutterPlugin) {
        super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger()))
        self.plugin = plugin
    }

    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let arguments = call.arguments as? NSDictionary
        switch call.method {
            case "getAllAuthCredentials":
                var allCredentials: [[String: Any?]] = []
                for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials {
                    var crendentials: [[String: Any?]] = []
                    for c in credentials {
                        let credential: [String: Any?] = c.value.toMap()
                        crendentials.append(credential)
                    }
                    if crendentials.count > 0 {
                        let dict: [String : Any] = [
                            "protectionSpace": protectionSpace.toMap(),
                            "credentials": crendentials
                        ]
                        allCredentials.append(dict)
                    }
                }
                result(allCredentials)
                break
            case "getHttpAuthCredentials":
                var crendentials: [[String: Any?]] = []
            
                let host = arguments!["host"] as! String
                let urlProtocol = arguments!["protocol"] as? String
                let urlPort = arguments!["port"] as? Int ?? 0
                var realm = arguments!["realm"] as? String
                if let r = realm, r.isEmpty {
                    realm = nil
                }

                for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials {
                    if protectionSpace.host == host && protectionSpace.realm == realm &&
                    protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort {
                        for c in credentials {
                            crendentials.append(c.value.toMap())
                        }
                        break
                    }
                }
                result(crendentials)
                break
            case "setHttpAuthCredential":
                let host = arguments!["host"] as! String
                let urlProtocol = arguments!["protocol"] as? String
                let urlPort = arguments!["port"] as? Int ?? 0
                var realm = arguments!["realm"] as? String
                if let r = realm, r.isEmpty {
                    realm = nil
                }
                let username = arguments!["username"] as! String
                let password = arguments!["password"] as! String
                let credential = URLCredential(user: username, password: password, persistence: .permanent)
                CredentialDatabase.credentialStore.set(credential,
                                    for: URLProtectionSpace(host: host, port: urlPort, protocol: urlProtocol,
                                                            realm: realm, authenticationMethod: NSURLAuthenticationMethodHTTPBasic))
                result(true)
                break
            case "removeHttpAuthCredential":
                let host = arguments!["host"] as! String
                let urlProtocol = arguments!["protocol"] as? String
                let urlPort = arguments!["port"] as? Int ?? 0
                var realm = arguments!["realm"] as? String
                if let r = realm, r.isEmpty {
                    realm = nil
                }
                let username = arguments!["username"] as! String
                let password = arguments!["password"] as! String
                
                var credential: URLCredential? = nil
                var protectionSpaceCredential: URLProtectionSpace? = nil
                
                for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials {
                    if protectionSpace.host == host && protectionSpace.realm == realm &&
                    protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort {
                        for c in credentials {
                            if c.value.user == username, c.value.password == password {
                                credential = c.value
                                protectionSpaceCredential = protectionSpace
                                break
                            }
                        }
                    }
                    if credential != nil {
                        break
                    }
                }
                
                if let c = credential, let protectionSpace = protectionSpaceCredential {
                    CredentialDatabase.credentialStore.remove(c, for: protectionSpace)
                }
                
                result(true)
                break
            case "removeHttpAuthCredentials":
                let host = arguments!["host"] as! String
                let urlProtocol = arguments!["protocol"] as? String
                let urlPort = arguments!["port"] as? Int ?? 0
                var realm = arguments!["realm"] as? String
                if let r = realm, r.isEmpty {
                    realm = nil
                }
                
                var credentialsToRemove: [URLCredential] = []
                var protectionSpaceCredential: URLProtectionSpace? = nil
                
                for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials {
                    if protectionSpace.host == host && protectionSpace.realm == realm &&
                    protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort {
                        protectionSpaceCredential = protectionSpace
                        for c in credentials {
                            if let _ = c.value.user, let _ = c.value.password {
                                credentialsToRemove.append(c.value)
                            }
                        }
                        break
                    }
                }
                
                if let protectionSpace = protectionSpaceCredential {
                    for credential in credentialsToRemove {
                        CredentialDatabase.credentialStore.remove(credential, for: protectionSpace)
                    }
                }
                
                result(true)
                break
            case "clearAllAuthCredentials":
                for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials {
                    for credential in credentials {
                        CredentialDatabase.credentialStore.remove(credential.value, for: protectionSpace)
                    }
                }
                result(true)
                break
            default:
                result(FlutterMethodNotImplemented)
                break
        }
    }
    
    public override func dispose() {
        super.dispose()
        plugin = nil
    }
    
    deinit {
        dispose()
    }
}
