//
//  RNGizUserManagerModule.swift
//  RNGizUserManagerModule
//
//  Copyright © 2022 Gizwits. All rights reserved.
//

import Foundation
import React
import GizwitsiOSSDK

struct ConnectParams: Decodable {
    var type: GizwitsiOSSDK.GizCapability
    var id: String
}
struct CheckUpdateParams: Decodable {
    var type: GizwitsiOSSDK.GizCapability
    var firmwareType: GizwitsiOSSDK.GizOTAFirmwareType
    var id: String
}
struct StartUpgradeParams: Decodable {
    var type: GizwitsiOSSDK.GizCapability
    var firmwareType: GizwitsiOSSDK.GizOTAFirmwareType
    var id: String
}
struct CancelUpgradeParams: Decodable {
    var type: GizwitsiOSSDK.GizCapability
    var id: String
}


struct RegisterParams: Decodable {
    var id: String
}

struct UnBindParams: Decodable {
    var id: String
}

struct GetDpParams: Decodable {
    var attrs: [String]?
    var id: String
    var type: GizwitsiOSSDK.GizCapability
}

struct BindParams: Decodable {
    var alias: String?
    var remark: String?
    var id: String
}
struct UpdateDeviceParams: Decodable {
    var alias: String?
    var remark: String?
    var id: String
}

struct GetDeviceInfoParams: Decodable {
    var id: String
    var type: GizwitsiOSSDK.GizCapability
}

struct WriteParams: Decodable {
    var type: GizwitsiOSSDK.GizCapability
    var id: String
    var data: String
}
struct ProvideWiFiCredentialsParams: Decodable {
    var type: GizwitsiOSSDK.GizCapability
    var id: String
    var ssid: String
    var password: String
    var timeout: Int
}
struct StopProvideWiFiCredentialsParams: Decodable {
    var type: GizwitsiOSSDK.GizCapability
    var id: String
}

struct QueryTimerParams: Decodable {
    var id: String
    var type: GizwitsiOSSDK.GizCapability
}
struct CreateTimerParams: Decodable {
    var id: String
    var type: GizwitsiOSSDK.GizCapability
    var data: GizwitsiOSSDK.GizDeviceLocalTimerParams
}
struct EditTimerParams: Decodable {
    var id: String
    var type: GizwitsiOSSDK.GizCapability
    var data: GizwitsiOSSDK.GizDeviceLocalTimerParams
}

struct DeleteTimerParams: Decodable {
    var id: String
    var timerId: Int
    var type: GizwitsiOSSDK.GizCapability
}


@objc(RNGizDeviceManagerModule)
class RNGizDeviceManagerModule: RCTEventEmitter  {
    
    override func supportedEvents() -> [String]! {
        return ["GizOTAProgressEvent", "GizProvideWiFiCredentialsEvent"]
    }
    
    private func findDevice(id: String) -> GizwitsiOSSDK.GizDevice? {
        let device = RNGizSDKManagerModule.devices.first { d in
            d.id == id
        }
        return device
    }
    
    @objc
    public func sendDp(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: WriteParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<GizJSON?, GizCtrlException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.sendDp(data: GizJSON(parseJSON: params.data))
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.sendDp(data: GizJSON(parseJSON: params.data))
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.sendDp(data: GizJSON(parseJSON: params.data))
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                    
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }

    @objc
    public func updateDeviceInfo(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: UpdateDeviceParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    let data = await device.updateDeviceInfo(alias: params.alias, remark: params.remark)
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    
    @objc
    public func bind(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: BindParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    let data = await device.bind(alias: params.alias ?? "", remark: params.remark ?? "")
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    @objc
    public func checkUpdate(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: CheckUpdateParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<GizCheckUpdateResultInfo, GizOTAException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.checkUpdate(firmwareType: params.firmwareType)
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.checkUpdate(firmwareType: params.firmwareType)
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.checkUpdate(firmwareType: params.firmwareType)
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    @objc
    public func cancelUpgrade(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: CancelUpgradeParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<Int?, GizOTAException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.cancelUpgrade()
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.cancelUpgrade()
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.cancelUpgrade()
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
        }
    }
    @objc
    public func startUpgrade(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: StartUpgradeParams.self) {
            
            
            // 先找到设备
            if let device = findDevice(id: params.id) {
                @Sendable func progressHandler(event: GizOTAProgressData) {
                    // 推送数据到 GizOTAProgressEvent
                    let data = [
                        "device": GizRNCallbackManager.convertToDictionary(object: device) ?? [:],
                        "data": GizRNCallbackManager.convertToDictionary(object: event) as Any
                    ] as [String : Any]
                    sendEvent(withName: "GizOTAProgressEvent", body: data)
                }
                Task {
                    var data: GizResult<Int?, GizOTAException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.startUpgrade(firmwareType: params.firmwareType, progressHandler: progressHandler)
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.startUpgrade(firmwareType: params.firmwareType, progressHandler: progressHandler)
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.startUpgrade(firmwareType: params.firmwareType, progressHandler: progressHandler)
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    public func unBind(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: UnBindParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    let data = await device.unBind()
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    @objc
    public func register(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: RegisterParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    let data = await device.register()
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    public func getDp(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: GetDpParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<GizJSON?, GizCtrlException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.getDp(attrs: params.attrs)
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.getDp(attrs: params.attrs)
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.getDp(attrs: params.attrs)
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                    
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }

    @objc
    public func getDeviceInfo(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: GetDeviceInfoParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<DeviceInfoProfile?, GizCtrlException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.getDeviceInfo()
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.getDeviceInfo()
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.getDeviceInfo()
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                    
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    public func connect(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: ConnectParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<Int?, GizConnectException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.connect()
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.connect()
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.connect()
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                    
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    @objc
    public func disConnect(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: ConnectParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<Int?, GizConnectException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.disConnect()
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.disConnect()
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.disConnect()
                        break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                    
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    public func provideWiFiCredentials(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: ProvideWiFiCredentialsParams.self) {
            
            
            // 先找到设备
            if let device = findDevice(id: params.id) {
                @Sendable func progressHandler(event: GizWiFiActivatorEvent, detail: GizWiFiActivatorEventDetail?) {
                    // 推送数据到 GizOTAProgressEvent
                    // data 包含 event 、code message, code 和 message 是可选的
                    let data = [
                        "device": GizRNCallbackManager.convertToDictionary(object: device) ?? [:],
                        "data": ["event": event.rawValue, "code": detail?.code, "message": detail?.message]
                    ] as [String : Any]
                    sendEvent(withName: "GizProvideWiFiCredentialsEvent", body: data)
                }
                Task {
                    var data: GizResult<GizBaseProfile?, GizActivatorException?>
                    switch(params.type) {
                        case .GizBleCapability:
                            data = await device.bleCapability.provideWiFiCredentials(ssid: params.ssid, password: params.password, timeout: params.timeout, processHandler: progressHandler)
                            break
                        case .GizLanCapability:
                            data = await device.lanCapability.provideWiFiCredentials(ssid: params.ssid, password: params.password, timeout: params.timeout, processHandler: progressHandler)
                            break
                        case .GizMQTTCapability:
                            data = await device.mqttCapability.provideWiFiCredentials(ssid: params.ssid, password: params.password, timeout: params.timeout, processHandler: progressHandler)
                            break
                    }
                    
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    public func stopProvideWiFiCredentials(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: StopProvideWiFiCredentialsParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<Int?, GizActivatorException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.stopProvideWiFiCredentials()
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.stopProvideWiFiCredentials()
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.stopProvideWiFiCredentials()
                        break
                    }
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
                
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
        }
    }

    @objc
    public func queryTimer(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: QueryTimerParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<[GizDeviceLocalTimerItem]?, GizAPIException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.queryTimer()
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.queryTimer()
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.queryTimer()
                        break
                    }
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    
    @objc
    public func deleteTimer(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: DeleteTimerParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<GizDeleteDeviceTimerResult, GizAPIException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.deleteTimer(id: params.timerId)
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.deleteTimer(id: params.timerId)
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.deleteTimer(id: params.timerId)
                        break
                    }
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    public func createTimer(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: CreateTimerParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<GizDeviceTimerResult, GizAPIException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.createTimer(data: params.data)
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.createTimer(data: params.data)
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.createTimer(data: params.data)
                        break
                    }
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    public func editTimer(_ options: NSDictionary, result: @escaping RCTResponseSenderBlock) {
        if let params = RNGizParamsChecker.check(options: options, result: result, paramsType: EditTimerParams.self) {
            // 先找到设备
            if let device = findDevice(id: params.id) {
                Task {
                    var data: GizResult<GizDeviceTimerResult, GizAPIException?>
                    switch(params.type) {
                    case .GizBleCapability:
                        data = await device.bleCapability.editTimer(data: params.data)
                        break
                    case .GizLanCapability:
                        data = await device.lanCapability.editTimer(data: params.data)
                        break
                    case .GizMQTTCapability:
                        data = await device.mqttCapability.editTimer(data: params.data)
                        break
                    }
                    GizRNCallbackManager.callbackWithResult(callback: result, result:data)
                }
            } else {
                // 提示设备不存在
                GizRNCallbackManager.callbackWithResult(callback: result, result: GizResult<Int?, GizAPIException?>(error: GizAPIException.GIZ_OPENAPI_DEVICE_NOT_FOUND))
            }
            
        }
    }
    
    @objc
    override static func requiresMainQueueSetup() -> Bool {
        return true
    }
}
