#import <Foundation/Foundation.h>
#import <Capacitor/Capacitor.h>
#import "CIDPrinter.h"
#import "InitResult.h"
#import "PrinterLibraryEvent.h"
#import "CIDPrint.h"

@implementation CIDPrint

#define LIBRARY_EVENT @"printerLibraryEvent"

CAPPluginCall *savedLastCall;

-(BOOL) hasRequiredPermissions:(NSArray<NSString*>*)permissions {
    return YES;
}

-(NSDictionary*) fromJSONObject:(NSDictionary*)jobj {
    NSMutableDictionary* dict = [[NSMutableDictionary alloc]initWithDictionary:jobj];
    return dict;
//    Iterator<String> keys = jobj.keys();
//    while(keys.hasNext()) {
//        String key = keys.next();
//        try {
//            if(jobj.get(key) instanceof JSONObject) {
//                jobj.put(key, fromJSONObject((JSONObject) jobj.get(key)));
//            }
//        } catch (JSONException e) {
//            Log.d(TAG, "fromJSONObject encounters an error in " + key + " error: " + e.getMessage());
//        }
//    }
//    return  JSObject.fromJSONObject(jobj);
}


-(void)handleSuccess:(PrinterLibraryEvent*)evt {
    switch([evt getAction]) {
        case LICENSE_ACTIVATION:
            if(savedLastCall != nil) {
                savedLastCall.successHandler([[CAPPluginCallResult alloc]init:[evt getJSONObject]], savedLastCall);
            }
            break;
        default:
            [self notifyListeners:LIBRARY_EVENT data:[evt getJSONObject]];
    }
}

-(void)handleError:(PrinterLibraryEvent*)evt {
    [self notifyListeners:LIBRARY_EVENT data:[evt getJSONObject]];
}

-(void)handleNotification:(PrinterLibraryEvent*)evt {
    [self notifyListeners:LIBRARY_EVENT data:[evt getJSONObject]];
}

-(void) initCIDPrinterLib:(CAPPluginCall*)call {
    NSLog(@"initCIDPrint");
    self._printerlibrary = CIDPrinter.getSharedObject;
    PrinterLibraryEvent* evt = nil;
    if(self._printerlibrary != nil) {
        [self._printerlibrary addListener:self];
        evt = [self._printerlibrary initialize];
        if([self hasRequiredPermissions:CIDPrinter.getRequiredPermissions]) {
            NSMutableDictionary<NSString*, id>* test;
            call.successHandler([[CAPPluginCallResult alloc]init:[evt getJSONObject]], call);
            return;
        }
        evt = [[PrinterLibraryEvent alloc]initWithResultClass:SUCCESS action:INITIALIZE data:[[InitResult alloc]initWithPermissions:CIDPrinter.getRequiredPermissions]];
        call.successHandler([[CAPPluginCallResult alloc]init:[evt getJSONObject]], call);
    } else {
        call.errorHandler([[CAPPluginCallError alloc]init:@"Failed to initialize printer plugin" code:@"" error:nil data:[[NSDictionary alloc]init]]);
    }
}

-(void) enableBluetoothPrinting:(CAPPluginCall*)call {
    if(self._printerlibrary != nil) {
        call.keepAlive = YES;
        savedLastCall = call;
        [self addCallback:@"enableBluetoothPrinting" callback:call];
        [self._printerlibrary enableBluetoothPrinting:[call.options objectForKey:@"enable"]];
    }
}

-(void)connectToPreferredPrinter:(CAPPluginCall*)call {
    if(self._printerlibrary != nil) {
        call.keepAlive = YES;
        [self addCallback:@"connectToPreferredPrinter" callback:call];
        [self._printerlibrary connectToPreferredPrinter:[call.options objectForKey:@"mac"]];
    }
}

-(void)printLabelWithObject:(CAPPluginCall*) call {
    if(self._printerlibrary != nil) {
        call.keepAlive = true;
        [self addCallback:@"printLabelWithObject" callback:call];
        [self._printerlibrary print:[call.options objectForKey:@"label"] params:[call.options objectForKey:@"data"]];
    }
}

-(void)printReceiptWithObject:(CAPPluginCall*) call {
    if(self._printerlibrary != nil) {
        call.keepAlive = true;
        [self addCallback:@"printReceiptWithObject" callback:call];
        [self._printerlibrary printReceipt:[call.options objectForKey:@"label"] params:[call.options objectForKey:@"data"]];
    }
}

-(void) printLabel:(CAPPluginCall*)call {
    if(self._printerlibrary != nil) {
        [self addCallback:@"printData" callback:call];
        [self._printerlibrary print:[call.options objectForKey:@"label"]];
    }
}

-(void) discoverDevices:(CAPPluginCall*)call {
    if(self._printerlibrary != nil) {
        call.keepAlive = YES;
        savedLastCall = call;
        [self addCallback:@"discoveredDevices" callback:call];
        [self._printerlibrary discoverDevices];
    }
}

-(void) addCallback:(NSString*)functionName callback:(CAPPluginCall*)callback {
    if(self._callbacks == nil) {
        self._callbacks = [[NSMutableDictionary alloc]initWithCapacity:1];
        [self._callbacks setObject:callback forKey:functionName];
    } else {
        [self._callbacks setObject:callback forKey:functionName];
    }
}

-(void)onPrinterLibraryEvent:(PrinterLibraryEvent*)event {
    switch([event getEventType]) {
        case SUCCESS:
            [self handleSuccess:event];
            break;
        case FAILED:
            [self handleError:event];
            break;
        case NOTIFY:
            [self handleNotification:event];
            break;
    }
}

-(void) activateLicense:(CAPPluginCall*)call {
    if(self._printerlibrary != nil) {
        [call save];
        savedLastCall = call;
        [self._printerlibrary activateLicense:[call.options valueForKey:@"licenseKey"] customerID:[call.options valueForKey:@"customerID"]];
    }
}

@end

//-(void) initCIDScannerLib:(CAPPluginCall*)call {
//    NSLog(@"initCaptureID");
//    // get display size
//    CGFloat width = [UIScreen mainScreen].bounds.size.width;
//    CGFloat height = [UIScreen mainScreen].bounds.size.height;
//
//    // run on main thread to init the UIView
//    dispatch_async(dispatch_get_main_queue(), ^{
//            self.previewView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, width, height)];
////            [self.previewView setBackgroundColor:[UIColor yellowColor]];
//            self.previewView.alpha = 0.0f;
//            //self.previewView.opaque = NO;
//            //self.previewView.backgroundColor = [UIColor clearColor];
//            UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
//            [currentWindow addSubview:self.previewView];
//        self.CPID_decoder = [[CaptureIDLibrary alloc]initWithUIview:self.previewView resultBlock:^(NSArray* result) {
//            [self notifyListeners:@"statusEvent" data:result[0]];
//        }];
//
//    });
//
//    package app.captureid.plugins.cidprint;
//
//    import android.content.Intent;
//    import android.util.Log;
//    import com.getcapacitor.JSObject;
//    import com.getcapacitor.NativePlugin;
//    import com.getcapacitor.Plugin;
//    import com.getcapacitor.PluginCall;
//    import com.getcapacitor.PluginMethod;
//    import com.getcapacitor.PluginResult;
//    import org.json.JSONException;
//    import org.json.JSONObject;
//    import java.util.HashMap;
//    import java.util.Iterator;
//    import androidx.appcompat.app.AppCompatActivity;
//    import app.captureid.cidprinterlibrary.CIDPrinter;
//    import app.captureid.cidprinterlibrary.connectors.BluetoothConnector;
//    import app.captureid.cidprinterlibrary.labels.ReferenceLabel;
//    import app.captureid.cidprinterlibrary.notifications.InitResult;
//    import app.captureid.cidprinterlibrary.notifications.PrinterLibraryEvent;
//    import app.captureid.cidprinterlibrary.notifications.PrinterLibraryListener;
//
//    @NativePlugin(
//            requestCodes={BluetoothConnector.REQUEST_ENABLE_BT}
//    )
//
//    public class CIDPrint extends Plugin {
//        private static final String TAG = CIDPrint.class.getSimpleName();
//
//        private static final String LIBRARY_EVENT = "printerLibraryEvent";
//
//        private CIDPrinter _printerlibrary;
//        private HashMap<String, PluginCall> _callbacks = new HashMap<String, PluginCall>();
//        private AppCompatActivity _activity;
//        private int _enableBluetoothRequestID;
//
//        public CIDPrint() {
//            super();
//        }
//
//        @Override
//        protected void handleOnResume() {
//            super.handleOnResume();
//            _activity = getActivity();
//        }
//
//        private PrinterLibraryListener _library_listener = new PrinterLibraryListener() {
//            @Override
//            public void onPrinterLibraryEvent(PrinterLibraryEvent event) {
//                switch(event.getEventType()) {
//                    case SUCCESS:
//                        handleSuccess(event);
//                        break;
//                    case FAILED:
//                        handleError(event);
//                        break;
//                    case NOTIFY:
//                        handleNotification(event);
//                        break;
//                }
//            }
//
//            @Override
//            public void requestForStartIntent(Intent intent, int requestID) {
//                _enableBluetoothRequestID = requestID;
//                startActivityForResult(savedLastCall, intent, requestID);
//            }
//        };
//
//        private void handleSuccess(PrinterLibraryEvent evt) {
//            JSObject obj = null;
//            try {
//                obj = fromJSONObject(evt.getJSONObject());
//            } catch (JSONException e) {
//                e.printStackTrace();
//            }
//            try {
//                switch(evt.getAction()) {
//                    case LICENSE_ACTIVATION:
//                        savedLastCall.success(obj);
//                    default:
//                        notifyListeners(LIBRARY_EVENT, obj);
//                }
//    //            switch (evt.getAction()) {
//    //                case DISCOVER:
//    //                    notifyListeners(LIBRARY_EVENT, obj);
//    ////                    _callbacks.get("discoverDevices").successCallback(result);
//    //                    break;
//    //                case CONNECT:
//    ////                    _callbacks.get("connectToPreferredPrinter").successCallback(result);
//    //                    break;
//    //                case PRINT:
//    //                    notifyListeners(LIBRARY_EVENT, obj);
//    //                    break;
//    //            }
//            } catch(Exception ex) {
//                Log.d(TAG, "handleSuccess: " + ex.getMessage());
//            }
//        }
//
//        private void handleError(PrinterLibraryEvent evt) {
//            JSObject obj = new JSObject();
//            try {
//                obj = fromJSONObject((evt.getJSONObject()));
//            } catch(JSONException ex) {
//                Log.d(TAG, "handleError: " + ex.getMessage());
//            }
//            notifyListeners(LIBRARY_EVENT, obj);
//        }
//
//        private void handleNotification(PrinterLibraryEvent evt) {
//            JSObject obj = new JSObject();
//            try {
//                obj = fromJSONObject(evt.getJSONObject());
//            } catch (JSONException ex) {
//                Log.d(TAG, "handleNotification: " + ex.getMessage());
//            }
//            notifyListeners(LIBRARY_EVENT, obj);
//        }
//
//        private void addCallback(String functionName, PluginCall callback) {
//            if(_callbacks.containsKey(functionName)) {
//                if(_callbacks.get(functionName).isReleased()) {
//                    _callbacks.remove(functionName);
//                    _callbacks.put(functionName, callback);
//                }
//            } else {
//                _callbacks.put(functionName, callback);
//            }
//        }
//
//        private boolean hasRequiredPermissions(String[] permissions) {
//            for(String permission: permissions) {
//                if(!hasPermission(permission)) {
//                    return false;
//                }
//            }
//            return true;
//        }
//
//        @PluginMethod
//        public void debugPrint(PluginCall call) {
//            _printerlibrary.debugPrint(call.getString("label"));
//        }
//
//        @PluginMethod
//        public void initCIDPrinterLib(PluginCall call) {
//            _printerlibrary = CIDPrinter.getSharedLibrary(_activity);
//            if(_printerlibrary != null) {
//                _printerlibrary.addListener(_library_listener);
//            }
//            PrinterLibraryEvent evt = _printerlibrary.initialize();
//            if(hasRequiredPermissions(CIDPrinter.getRequiredPermissions())) {
//                try {
//                    call.success(fromJSONObject(evt.getJSONObject()));
//                } catch (JSONException e) {
//                    call.error("initCIDPrinterLib encountered an error: " + e.getMessage());
//                }
//                return;
//            }
//            evt = new PrinterLibraryEvent(PrinterLibraryEvent.EventType.SUCCESS, PrinterLibraryEvent.LibraryActionType.INITIALIZE, new InitResult(CIDPrinter.getRequiredPermissions()));
//            try {
//                call.success(fromJSONObject(evt.getJSONObject()));
//            } catch (JSONException e) {
//                call.error("initCIDPrinterLib encountered an error: " + e.getMessage());
//            }
//        }
//
//        @PluginMethod
//        public void closeCIDPrinterLib(PluginCall call) {
//            if(_printerlibrary != null) {
//                _printerlibrary.closeSharedlibrary();
//            }
//        }
//
//        @PluginMethod
//
//        @PluginMethod
//        public void enableBluetoothPrinting (PluginCall call) {
//            if(_printerlibrary != null) {
//                saveCall(call);
//                addCallback("enableBluetoothPrinting", call);
//                _printerlibrary.enableBluetoothPrinting(call.getBoolean("enable"));
//            }
//        }
//
//        @PluginMethod
//        public void getPairedDevices(PluginCall call) {
//            if(_printerlibrary != null) {
//                addCallback("getPairedDevices", call);
//                _printerlibrary.getPairedDevices();
//            }
//        }
//
//        @PluginMethod
//        public void discoverDevices(PluginCall call) {
//            if(_printerlibrary != null) {
//                addCallback("discoverDevices", call);
//                _printerlibrary.discoverDevices();
//            }
//        }
//
//        @PluginMethod
//        public void printReferenceLabel(PluginCall call) {
//            if(_printerlibrary != null) {
//                _printerlibrary.printReferenceLabel(ReferenceLabel.ReferenceLabelType.values()[call.getInt("labeltype", 0)]);
//            }
//        }
//
//        @PluginMethod
//        public void printData(PluginCall call) {
//            if(_printerlibrary != null) {
//                addCallback("printData", call);
//                _printerlibrary.print(call.getString("data").getBytes(), false);
//            }
//        }
//
//        @PluginMethod
//        public void printNativeData(PluginCall call) {
//            if(_printerlibrary != null) {
//                addCallback("printNativeData", call);
//                _printerlibrary.print(call.getString("data").getBytes(), true);
//            }
//        }
//
//        @PluginMethod
//        public void printLabelWithObject(PluginCall call) {
//            try {
//                if (_printerlibrary != null) {
//                    addCallback("printLabelWithObject", call);
//                    _printerlibrary.print(call.getString("label"), call.getData(). getJSONObject("data").getJSONObject("variables"));
//                }
//            } catch(JSONException ex) {
//                Log.d(TAG, "printLabelWithData: " + ex.getMessage());
//            } catch(ClassCastException ex) {
//                Log.d(TAG, "printLabelWithData: " + ex.getMessage());
//            } catch(Exception ex) {
//                Log.d(TAG, "printLabelWithData: " + ex.getMessage());
//            }
//        }
//
//        @PluginMethod
//        public void printLabelWithData(PluginCall call) {
//            try {
//                if (_printerlibrary != null) {
//                    addCallback("printLabelWithData", call);
//                    _printerlibrary.print(call.getString("label"), call.getArray("data").toList().toArray(new String[call.getArray("data").toList().size()]));
//                }
//            } catch(JSONException ex) {
//                Log.d(TAG, "printLabelWithData: " + ex.getMessage());
//            } catch(ClassCastException ex) {
//                Log.d(TAG, "printLabelWithData: " + ex.getMessage());
//            } catch(Exception ex) {
//                Log.d(TAG, "printLabelWithData: " + ex.getMessage());
//            }
//        }
//
//        @PluginMethod
//        public void getPrinterStatus(PluginCall call) {
//            if(_printerlibrary != null) {
//                _printerlibrary.getStatus();
//            }
//        }
//
//        @PluginMethod
//        public void setupMediaSize(PluginCall call) {
//            if(_printerlibrary != null) {
//                _printerlibrary.setupMediaSize(call.getInt("width"), call.getInt("height"));
//            }
//        }
//
//        @PluginMethod
//        public void enableDispendingMode(PluginCall call) {
//            if(_printerlibrary != null) {
//                _printerlibrary.enableDispensingMode(call.getBoolean("enable"));
//            }
//        }
//
//        @PluginMethod
//        public void printLabel(PluginCall call) {
//            if(_printerlibrary != null) {
//                addCallback("printData", call);
//                _printerlibrary.print(call.getString("label"));
//            }
//        }
//
//        @PluginMethod
//        public void disconnectFromPrinter(PluginCall call) {
//            if(_printerlibrary != null) {
//                _printerlibrary.disconnectPrinter();
//            }
//        }

//
//        @Override
//        protected void handleOnActivityResult(int requestCode, int resultCode, Intent data) {
//            super.handleOnActivityResult(requestCode, resultCode, data);
//            if(_printerlibrary != null) {
//                _printerlibrary.handleOnActivityResult(requestCode, resultCode, data);
//            }
//        }
//
//        @Override
//        protected void handleOnRestart() {
//            super.handleOnRestart();
//            if(_printerlibrary != null) {
//                _printerlibrary.onResume();
//            }
//        }
//
//        @Override
//        protected void handleOnPause() {
//            if(_printerlibrary !=  null) {
//                _printerlibrary.onPause();
//            }
//            super.handleOnPause();
//        }
//
//        @Override
//        protected void handleOnDestroy() {
//            if(_printerlibrary != null) {
//                _printerlibrary.onDestroy();
//            }
//             super.handleOnDestroy();
//        }
//
//        private JSObject fromJSONObject(JSONObject jobj) throws JSONException {
//            Iterator<String> keys = jobj.keys();
//            while(keys.hasNext()) {
//                String key = keys.next();
//                try {
//                    if(jobj.get(key) instanceof JSONObject) {
//                        jobj.put(key, fromJSONObject((JSONObject) jobj.get(key)));
//                    }
//                } catch (JSONException e) {
//                    Log.d(TAG, "fromJSONObject encounters an error in " + key + " error: " + e.getMessage());
//                }
//            }
//            return  JSObject.fromJSONObject(jobj);
//        }
//    }
