import os.log
import NemonicSdk
import UIKit

@objc(NPrinterControllerModule)
class NPrinterControllerModule: RCTEventEmitter {
    
    private var printerController: NPrinterController = NPrinterController()

    private var printer: NPrinter?
    
    @objc(init)
    override init() {
        super.init()
        printerController = NPrinterController(self)
    }
    
    @objc(getBleConnectDelayOffset:withRejecter:)
    func getBleConnectDelayOffset(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        resolve(0)
    }
    
    @objc(setBleConnectDelayOffset:)
    func setBleConnectDelayOffset(params: NSDictionary) -> Void {
    }
    
    @objc(getBleSendRetryDelayOffset:withRejecter:)
    func getBleSendRetryDelayOffset(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        resolve(0)
    }
    
    @objc(setBleSendRetryDelayOffset:)
    func setBleSendRetryDelayOffset(params: NSDictionary) -> Void {
    }
    
    @objc(getDefaultConnectDelay:withRejecter:)
    func getDefaultConnectDelay(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let delay = printerController.getDefaultConnectDelay()
        resolve(delay)
    }
    
    @objc(getConnectDelay:withRejecter:)
    func getConnectDelay(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let delay = printerController.getConnectDelay()
        resolve(delay)
    }
    
    @objc(setConnectDelay:)
    func setConnectDelay(params: NSDictionary) -> Void {
        let msec = UInt32(params["msec"] as! Int)
        printerController.setConnectDelay(msec)
    }
    
    @objc(connect:withResolver:withRejecter:)
    func connect(params: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        
        let name = params["name"] as! String
        let macAddress = params["macAddress"] as! String
        let type = params["type"] as! Int
        let queueLabel = params["queueLabel"] as! String?
        
        let printer = NPrinter();
        printer.setName(name)
        _ = printer.setMacAddress(macAddress)
        printer.setType(NPrinterType(rawValue: type) ?? .none)

        let result = printerController.connect(printer, queueLabel: queueLabel)

        if result == NemonicSdk.NResult.ok.rawValue {
            self.printer = printer
        }
        
        resolve(result)
    }

    @objc(disconnect)
    func disconnect() -> Void {
        printerController.disconnect()
        printer = nil
    }
    
    @objc(getConnectState:withRejecter:)
    func getConnectState(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let result = printerController.getConnectState()
        resolve(result)
    }
    
    @objc(cancel)
    func cancel() -> Void {
        printerController.cancel()
    }
    
    @objc(setPrintTimeout:)
    func setPrintTimeout(params: NSDictionary) -> Void {
        let enableAuto = params["enableAuto"] as! Bool
        let manualTime = params["manualTime"] as! Int
        
        printerController.setPrintTimeout(enableAuto, manualTime)
    }
    
    @objc(print:withResolver:withRejecter:)
    func print(params: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let imageData = params["images"] as! NSArray
        let imageUrls = params["imageUrls"] as! NSArray
        
        let quality = NemonicSdk.NPrintQuality(rawValue: params["quality"] as! Int)
        let copies = params["copies"] as! Int
        let isLastPageCut = params["isLastPageCut"] as! Bool
        let enableDither = params["enableDither"] as! Bool
        let isCheckPrinterStatus = params["isCheckPrinterStatus"] as! Bool
        let isCheckCartridgeType = params["isCheckCartridgeType"] as! Bool
        let isCheckPower = params["isCheckPower"] as! Bool
        
        let images = getImages(imageData: imageData, imageUrls: imageUrls)
        let printInfo = NPrintInfo(printer: printer!, images: images)
        _ = printInfo.setPrintQuality(quality!)
            .setCopies(copies)
            .setEnableLastPageCut(isLastPageCut)
            .setEnableDither(enableDither)
            .setEnableCheckPrinterStatus(isCheckPrinterStatus)
            .setEnableCheckCartridgeType(isCheckCartridgeType)
            .setEnableCheckPower(isCheckPower)
        
        let result = printerController.print(printInfo)
        resolve(result)
    }

    private func getImages(imageData: NSArray, imageUrls: NSArray) -> [UIImage] {
        var result = [UIImage]()
        
        if imageData.count > 0 {
            for i in 0..<imageData.count {
                let imageArray = imageData[i] as! NSArray
                var imageArrayUint8 = [UInt8](Array(repeating: 0, count: imageArray.count))
                
                for j in 0..<imageArray.count {
                    imageArrayUint8[j] = UInt8((imageArray[j] as! Int) & 0xff)
                }
                
                let data = NSData(bytes: imageArrayUint8, length: imageArrayUint8.count)
                let image = UIImage(data: data as Data)
                result.append(image!)
            }
        }
        else {
            for i in 0..<imageUrls.count {
                let imageUrl = imageUrls[i] as! String
                let url = URL(string: imageUrl)
                let data = try? Data(contentsOf: url!)
                let image = UIImage(data: data!)
                result.append(image!)
            }
        }
        
        return result
    }

    @objc(setTemplate:withResolver:withRejecter:)
    func setTemplate(params: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let imageArray = params["image"] as! NSArray
        let withPrint = params["withPrint"] as! Bool
        let enableDither = params["enableDither"] as! Bool

        var imageArrayUint8 = [UInt8](Array(repeating: 0, count: imageArray.count))
                
        for j in 0..<imageArray.count {
            imageArrayUint8[j] = UInt8((imageArray[j] as! Int) & 0xff)
        }
        
        let data = NSData(bytes: imageArrayUint8, length: imageArrayUint8.count)
        let image = UIImage(data: data as Data)
        
        let result = printerController.setTemplate(image!, withPrint: withPrint, enableDither: enableDither)
        resolve(result)
    }

    @objc(setTemplateWithUrl:withResolver:withRejecter:)
    func setTemplateWithUrl(params: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let imageUrl = params["imageUrl"] as! String
        let withPrint = params["withPrint"] as! Bool
        let enableDither = params["enableDither"] as! Bool
        
        let url = URL(string: imageUrl)
        let data = try? Data(contentsOf: url!)
        let image = UIImage(data: data!)
        
        let result = printerController.setTemplate(image!, withPrint: withPrint, enableDither: enableDither)
        resolve(result)
    }
    
    @objc(clearTemplate:withRejecter:)
    func clearTemplate(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let result = printerController.clearTemplate()
        resolve(result)
    }
    
    @objc(getPrinterStatus:withRejecter:)
    func getPrinterStatus(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let result = printerController.getPrinterStatus()
        resolve(result)
    }
    
    @objc(getCartridgeType:withRejecter:)
    func getCartridgeType(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let result = printerController.getCartridgeType()
        resolve(result)
    }
    
    @objc(getPrinterName:withRejecter:)
    func getPrinterName(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let result = printerController.getPrinterName()
        var resultParams = Dictionary<String, Any>()
        resultParams["result"] = result.getResult()
        resultParams["value"] = result.getValue()
        resolve(resultParams)
    }
    
    @objc(getBatteryLevel:withRejecter:)
    func getBatteryLevel(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let result = printerController.getBatteryLevel()
        resolve(result)
    }
    
    @objc(getBatteryStatus:withRejecter:)
    func getBatteryStatus(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
        let result = printerController.getBatteryStatus()
        resolve(result)
    }

    @objc
    override static func requiresMainQueueSetup() -> Bool {
        return true
    }
    
    @objc
    override func supportedEvents() -> [String]! {
        return [ "disconnected", "printProgress", "printComplete" ];
    }
}

extension NPrinterControllerModule: NPrinterControllerDelegate {
    func disconnected() {
        sendEvent(withName: "disconnected", body: nil)
    }
    
    func printProgress(index: Int, total: Int, result: Int) {
        var params = Dictionary<String, Any>()
        params["index"] = index
        params["total"] = total
        params["result"] = result
        sendEvent(withName: "printProgress", body: params)
    }
    
    func printComplete(result: Int) {
        var params = Dictionary<String, Any>()
        params["result"] = result
        sendEvent(withName: "printComplete", body: params)
    }
}
