//
//  FLTCocosViewController.swift
//  flutter_cocos_widget
//
//  Created by Rex Raphael on 30/01/2021.
//

import Foundation


// Defines cocos controllable from Flutter.
public class FLTCocosWidgetController: NSObject, FLTCocosOptionsSink, FlutterPlatformView {
    private var _rootView: FLTCocosView
    private var viewId: Int64 = 0
    private var channel: FlutterMethodChannel?
    private weak var registrar: (NSObjectProtocol & FlutterPluginRegistrar)?
    
    private var _disposed = false

    init(
        frame: CGRect,
        viewIdentifier viewId: Int64,
        arguments args: Any?,
        registrar: NSObjectProtocol & FlutterPluginRegistrar
    ) {

        //CGRect(x: 0, y: 0, width: 700, height: 700)
        self._rootView = FLTCocosView(frame: frame)
        super.init()
        
        globalControllers.append(self)

        self.viewId = viewId

        let channelName = String(format: "plugin.gem.com/cocos_view_%lld", viewId)
        self.channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger())

        self.channel?.setMethodCallHandler(self.methodHandler)
        self.attachView()
    }

    func methodHandler(_ call: FlutterMethodCall, result: FlutterResult) {
        
        NSLog("call : \(call.method)")
        if call.method == "cocos#dispose" {
            self.dispose()
            result(nil)
        } else {
            self.reattachView()
            if call.method == "cocos#isReady" {
                result(GetCocosPlayerUtils().cocosIsInitiallized())
            } else if call.method == "cocos#isLoaded" {
                let _isUnloaded = GetCocosPlayerUtils().isCocosLoaded()
                result(_isUnloaded)
            } else if call.method == "cocos#createCocosPlayer" {
                startCocosIfNeeded()
                result(nil)
            } else if call.method == "cocos#isPaused" {
                let _isPaused = GetCocosPlayerUtils().isCocosPaused()
                result(_isPaused)
            } else if call.method == "cocos#pausePlayer" {
                GetCocosPlayerUtils().pause()
                result(nil)
            } else if call.method == "cocos#postMessage" {
                self.postMessage(call: call, result: result)
                result(nil)
            } else if call.method == "cocos#resumePlayer" {
                GetCocosPlayerUtils().resume()
                result(nil)
            } else if call.method == "cocos#unloadPlayer" {
                GetCocosPlayerUtils().unload()
                result(nil)
            } else if call.method == "cocos#quitPlayer" {
                GetCocosPlayerUtils().quit()
                result(nil)
            } else if call.method == "cocos#waitForCocos" {
                result(nil)
            } else {
                result(FlutterMethodNotImplemented)
            }
        }
    }

    func setDisabledUnload(enabled: Bool) {

    }

    public func view() -> UIView {
        return _rootView;
    }

    private func startCocosIfNeeded() {
        GetCocosPlayerUtils().createPlayer(completed: { [self] (view: UIView?) in
           
        })
    }

    func attachView() {
        startCocosIfNeeded()
        //GetCocosPlayerUtils().ufw?.setCocosView(_rootView)
       // self.channel?.invokeMethod("events#onViewReattached", arguments: "")
         let cocosView = GetCocosPlayerUtils().ufw?.getCocosView()
         if let superview = cocosView?.superview {
             cocosView?.removeFromSuperview()
             superview.layoutIfNeeded()
         }

         if let cocosView = cocosView {
             _rootView.addSubview(cocosView)
             _rootView.layoutIfNeeded()
             self.channel?.invokeMethod("events#onViewReattached", arguments: "")
         }
        GetCocosPlayerUtils().resume()
    }

    func reattachView() {
        //todo 
        let cocosView = GetCocosPlayerUtils().ufw?.getCocosView()
        let superview = cocosView?.superview
        if superview != _rootView {
            attachView()
         }

        GetCocosPlayerUtils().resume()
    }

    func removeViewIfNeeded() {
        if GetCocosPlayerUtils().ufw == nil {
            return
        }

        let cocosView = GetCocosPlayerUtils().ufw?.getCocosView()
        if _rootView == cocosView?.superview {
            if globalControllers.isEmpty {
                cocosView?.removeFromSuperview()
                cocosView?.superview?.layoutIfNeeded()
            } else {
                globalControllers.last?.reattachView()
            }
        }
        GetCocosPlayerUtils().resume()
    }

    func dispose() {
        if _disposed {
            return
        }

        globalControllers.removeAll{ value in
            return value == self
        }

        channel?.setMethodCallHandler(nil)
        removeViewIfNeeded()
        
        _disposed = true
    }
    
    /// Handles messages from cocos in the current view
    func handleMessage(message: String) {
        self.channel?.invokeMethod("events#onCocosMessage", arguments: message)
    }
    
    
    /// Handles scene changed event from cocos in the current view
    func handleSceneChangeEvent(info: Dictionary<String, Any>) {
        self.channel?.invokeMethod("events#onCocosSceneLoaded", arguments: info)
    }
    
    /// Post messages to cocos from flutter
    func postMessage(call: FlutterMethodCall, result: FlutterResult) {
        guard let args = call.arguments else {
            result("iOS could not recognize flutter arguments in method: (postMessage)")
            return
        }

        if let myArgs = args as? [String: Any],
           let gObj = myArgs["gameObject"] as? String,
           let method = myArgs["methodName"] as? String,
           let message = myArgs["message"] as? String {
            GetCocosPlayerUtils().postMessageToCocos(gameObject: gObj, cocosMethodName: method, cocosMessage: message)
            result(nil)
        } else {
            result(FlutterError(code: "-1", message: "iOS could not extract " +
                   "flutter arguments in method: (postMessage)", details: nil))
        }
    }
}