/*
 Copyright 2021. Huawei Technologies Co., Ltd. All rights reserved.
 
 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
 
 https://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 AGConnectFunction
@objc(CordovaAGCCloudFunctions) class CordovaAGCCloudFunctions : CDVPlugin {
    /// All the AGC CloudFunctions API's can be reached via AGCCloudFunctionsViewModel class instance
    private lazy var viewModel: AGCCloudFunctionsViewModel = AGCCloudFunctionsViewModel();
    private let ERROR_PARAMETER_MESSAGE = "Error arguments paramater. methodName : "
    override func pluginInitialize() {
        super.pluginInitialize()
    }
    enum MethodName: String {
        case call
    }
    // MARK: - CloudFunctionsModule
    @objc(CloudFunctionsModule:)
    func CloudFunctionsModule(command: CDVInvokedUrlCommand){
        AGCCloudFunctionsLog.debug(#function) {
            guard let methodName = command.arguments[0] as? String else{
                sendError(
                    message: "Error CloudFunctionsModule name paramater. Should be module name: CloudFunctionsModule",
                    command.methodName, command.callbackId
                )
                return
            }
            guard let argsArray = command.arguments[1] as? NSArray else{
                sendError(message: "Error arguments array. methodName : ", methodName, command.callbackId)
                return
            }
            guard let args = argsArray[0] as? [String : Any] else{
                sendError(message: ERROR_PARAMETER_MESSAGE, methodName, command.callbackId)
                return
            }
            switch methodName {
            case MethodName.call.rawValue:
                // MARK: - call
                AGCCloudFunctionsLog.showInPanel(message: methodName, type: .call)
                guard let triggerIdentifier = args["triggerIdentifier"] as? String else{
                    sendError(message: "triggerIdentifier should not be empty. ", methodName, command.callbackId)
                    return
                }
                if(triggerIdentifier == ""){
                    sendError(message: "triggerIdentifier should not be empty. ", methodName, command.callbackId)
                    AGCCloudFunctionsLog.showInPanel(message: methodName, type: .fail)
                    return
                }
                let options = args["options"] as? [String : Any]
                let functionCallable: AGCFunctionCallable = AGCFunction.getInstance().wrap(triggerIdentifier);
                if let timeout = options?["timeout"] as? Double {
                    functionCallable.timeoutInterval = timeout
                }
                
                if let params = options?["params"] {
                    callFunction(functionCallable: functionCallable, param: params, command: command)
                }else {
                    callFunction(functionCallable: functionCallable, command: command)
                }
                AGCCloudFunctionsLog.showInPanel(message: methodName, type: .success)
                
            default:
                sendError(message: "Error method name. methodName : ", methodName, command.callbackId)
            }
        }
    }
    func sendError(message: String, _ methodName: String, _ callbackId: String){
        self.commandDelegate!.send(CDVPluginResult (
            status: CDVCommandStatus_ERROR,
            messageAs: message + methodName
        ), callbackId: callbackId)
    }
    
    
    // MARK: - Private Helper Functions
    
    /// Calls a function without input parameters.
    /// - Parameters:
    ///   - functionCallable: AGCFunctionCallable instance that is used to call cloud function.
    /// - Returns: Void
    private func callFunction(functionCallable: AGCFunctionCallable, command: CDVInvokedUrlCommand){
        viewModel.callFunction(functionCallable: functionCallable){ [weak self] (result, error) in
            guard let strongSelf = self else {return}
            if let error = error as NSError? {
                AGCCloudFunctionsLog.showInPanel(message: command.methodName, type: .fail)
                strongSelf.commandDelegate.send(CDVPluginResult (
                    status: CDVCommandStatus_ERROR,
                    messageAs: "\(error)"
                ), callbackId: command.callbackId)
            }
            if let result = result as? String {
                AGCCloudFunctionsLog.showInPanel(message: command.methodName, type: .success)
                strongSelf.commandDelegate.send(CDVPluginResult(
                    status: CDVCommandStatus_OK,
                    messageAs: result
                ), callbackId: command.callbackId)
            }
        }
    }
    
    /// Calls a function with input parameters.
    /// - Parameters:
    ///   - functionCallable: AGCFunctionCallable instance that is used to call cloud function
    ///   - param: Input parameter values of a function.
    /// - Returns: Void
    private func callFunction(functionCallable: AGCFunctionCallable,
                              param: Any, command: CDVInvokedUrlCommand
    ){
        viewModel.callFunction(functionCallable: functionCallable, param: param){ [weak self] (result, error) in
            guard let strongSelf = self else {return}
            if let error = error as NSError? {
                AGCCloudFunctionsLog.showInPanel(message: command.methodName, type: .fail)
                strongSelf.commandDelegate.send(CDVPluginResult (
                    status: CDVCommandStatus_ERROR,
                    messageAs: "\(error)"
                ), callbackId: command.callbackId)
            }
            if let result = result as? String {
                AGCCloudFunctionsLog.showInPanel(message: command.methodName, type: .success)
                strongSelf.commandDelegate.send(CDVPluginResult(
                    status: CDVCommandStatus_OK,
                    messageAs: result
                ), callbackId: command.callbackId)
            }
        }
    }
}
