#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTView.h>
#import <React/UIView+React.h>
#import <React/RCTUtils.h>


#import "EpsonTm.h"
#import "ePOS2.h"
#import "PrinterInfo.h"
#import "ShowMsg.h"

#define KEY_RESULT                  @"Result"
#define KEY_METHOD                  @"Method"
#define PAGE_AREA_HEIGHT    500
#define PAGE_AREA_WIDTH     500
#define FONT_A_HEIGHT       24
#define FONT_A_WIDTH        12
#define BARCODE_HEIGHT_POS  70
#define BARCODE_WIDTH_POS   110

@interface EpsonTm  () <Epos2PtrReceiveDelegate>
{
    Epos2Printer *printer_;
    
    PrinterInfo *printerInfo_;
    NSString *connectionSting;
}
@end

@implementation EpsonTm

RCT_EXPORT_MODULE()

- (instancetype)init
{
        // Initialize self
        printer_ = nil;
        
        printerInfo_ = [PrinterInfo sharedPrinterInfo];
    return self;

}
- (BOOL)initializeObject
{
    printer_ = [[Epos2Printer alloc] initWithPrinterSeries:printerInfo_.printerSeries lang:printerInfo_.lang];
    
    if (printer_ == nil) {
        [ShowMsg showErrorEpos:EPOS2_ERR_PARAM method:@"initiWithPrinterSeries"];
        return NO;
    }
    
    [printer_ setReceiveEventDelegate:self];
    
    return YES;
}
+ (BOOL)requiresMainQueueSetup
{
    return YES;  // only do this if your module initialization relies on calling UIKit!
}


RCT_EXPORT_METHOD(addTextSize:(long)width withHeight:(long)height  addTextFontResolver: (RCTPromiseResolveBlock)resolve
                 addTextFontRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addTextSize:width height:height];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addTextSize" }]);
    }
}

RCT_EXPORT_METHOD(addTextFont:(int)font  addTextFontResolver: (RCTPromiseResolveBlock)resolve
                 addTextFontRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addTextFont:font];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addTextFont" }]);
    }
}


RCT_EXPORT_METHOD(addTextStyle:(int)style withUL:(int)ul withem:(int)em withcolor:(int)color  addTextStyleResolver: (RCTPromiseResolveBlock)resolve
                 addTextStyleRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addTextStyle:style ul:ul em:em color:color];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addTextStyle" }]);
    }
}


RCT_EXPORT_METHOD(addFeedLine:(int)line addFeedLineResolver: (RCTPromiseResolveBlock)resolve
                 addFeedLineRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addFeedLine:line];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addFeedLine" }]);
    }
}


RCT_EXPORT_METHOD(addTextToPrint:(NSString *)stringTest addTextWithResolver: (RCTPromiseResolveBlock)resolve
                 addTextWithRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addText:stringTest];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addText" }]);
    }
}
RCT_EXPORT_METHOD(addLangToPrint:(int)lang addTextWithResolver: (RCTPromiseResolveBlock)resolve
                 addTextWithRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addTextLang:lang];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addText" }]);
    }
}

RCT_EXPORT_METHOD(addImage:(UIImage *)img withx:(long)x withY:(long)y withWidth:(long)width withheight:(long)height withcolor:(int)color withmode:(int)mode withhalftone:(int)halftone withbrightness:(double)brightness withcompress:(int)compress addImageResolver: (RCTPromiseResolveBlock)resolve
                 addImageRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addImage:img x:x y:y width:width height:height color:color mode:mode halftone:halftone brightness:brightness compress:compress];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addImage" }]);
    }
}


RCT_EXPORT_METHOD(addTextAlign:(int)align addTextAlignResolver: (RCTPromiseResolveBlock)resolve
                 addTextAlignRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addTextAlign:align];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addTextAlign" }]);
    }
}


RCT_EXPORT_METHOD(addPagePosition:(long)x withY:(long)y  addPagePositionResolver: (RCTPromiseResolveBlock)resolve
                 addPagePositionRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addPagePosition:x y:y];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addPagePosition" }]);
    }
}


RCT_EXPORT_METHOD(addPageArea:(long)x withY:(long)y withWidth:(long)width withheight:(long)height addPageAreaResolver: (RCTPromiseResolveBlock)resolve
                 addPageAreaRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addPageArea:x y:y width:width height:height];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addPageArea" }]);
    }
}


RCT_EXPORT_METHOD(addPulse:(int)drawer withTest:(int)time addTextWithResolver: (RCTPromiseResolveBlock)resolve
                 addTextWithRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addPulse:drawer time:time];

    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addPulse" }]);
    }
}


RCT_REMAP_METHOD(addPageEnd,addPageEndResolver: (RCTPromiseResolveBlock)resolve
                 addPageEndWithRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addPageEnd];
    
    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addPageEnd" }]);
    }
}


RCT_REMAP_METHOD(addPageBegin, addPageBeginResolver: (RCTPromiseResolveBlock)resolve
                 addPageBeginWithRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addPageBegin];
    
    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addPageBegin" }]);
    }
}


RCT_REMAP_METHOD(addCut, addCutWithResolver: (RCTPromiseResolveBlock)resolve
                 addCutWithRejecter:(RCTPromiseRejectBlock)reject)
{
    int result = EPOS2_SUCCESS;
    
    result = [printer_ addCut:EPOS2_CUT_FEED];
    
    if( result == EPOS2_SUCCESS) {
        resolve(@(result));
    } else {
        reject(@"no_events", @"There were no events", [NSError errorWithDomain:@"com.companyname.app" code:result userInfo:@{ @"method": @"addCut" }]);
    }
}
RCT_EXPORT_METHOD(initialSetup:(NSDictionary *)dicData callback:(RCTResponseSenderBlock)callback)
{
    connectionSting = dicData[@"ipAddress"];
    printerInfo_.lang = [dicData[@"lang"] intValue];
    printerInfo_.printerSeries = [dicData[@"printerSeries"] intValue];

    if (![self initializeObject]) {
        callback(@[@"error1", @""]);
    }else {
     callback(@[[NSNull null], @"done"]);
    }
    
//    if (![self createCouponData]) {
//        [self finalizeObject];
//        callback(@[@"error2", @""]);
//    }
//
//    if (![self printData]) {
//        [self finalizeObject];
//        callback(@[@"error3", @""]);
//    }
    
}
RCT_EXPORT_METHOD(sendPrint:(RCTResponseSenderBlock)callback) {
    
    if (![self printData]) {
            [self finalizeObject];
            callback(@[@"error Print", @""]);
    }
    else {
    callback(@[[NSNull null], @"done"]);
    }

}

- (BOOL)createCouponData
{
    int result = EPOS2_SUCCESS;
    
    const int barcodeWidth = 2;
    const int barcodeHeight = 64;
    
    if (printer_ == nil) {
        return NO;
    }
    
//    UIImage *coffeeData = [UIImage imageNamed:@"coffee.png"];
//    UIImage *wmarkData = [UIImage imageNamed:@"wmark.png"];
//
//    if (coffeeData == nil || wmarkData == nil) {
//        return NO;
//    }
    
    result = [printer_ addPageBegin];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addPageBegin"];
        return NO;
    }
    
    result = [printer_ addPageArea:0 y:0 width:PAGE_AREA_WIDTH height:PAGE_AREA_HEIGHT];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addPageArea"];
        return NO;
    }
    
    result = [printer_ addPageDirection:EPOS2_DIRECTION_TOP_TO_BOTTOM];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addPageDirection"];
        return NO;
    }
    
//    result = [printer_ addPagePosition:0 y:coffeeData.size.height];
//    if (result != EPOS2_SUCCESS) {
//        [ShowMsg showErrorEpos:result method:@"addPagePosition"];
//        return NO;
//    }
    
//    result = [printer_ addImage:coffeeData x:0 y:0
//                          width:coffeeData.size.width
//                         height:coffeeData.size.height
//                          color:EPOS2_PARAM_DEFAULT
//                           mode:EPOS2_PARAM_DEFAULT
//                       halftone:EPOS2_PARAM_DEFAULT
//                     brightness:3
//                       compress:EPOS2_PARAM_DEFAULT];
//    if (result != EPOS2_SUCCESS) {
//        [ShowMsg showErrorEpos:result method:@"addImage"];
//        return NO;
//    }
    
//    result = [printer_ addPagePosition:0 y:wmarkData.size.height];
//    if (result != EPOS2_SUCCESS) {
//        [ShowMsg showErrorEpos:result method:@"addPagePosition"];
//        return NO;
//    }
//
//    result = [printer_ addImage:wmarkData x:0 y:0
//                          width:wmarkData.size.width
//                         height:wmarkData.size.height
//                          color:EPOS2_PARAM_DEFAULT
//                           mode:EPOS2_PARAM_DEFAULT
//                       halftone:EPOS2_PARAM_DEFAULT
//                     brightness:EPOS2_PARAM_DEFAULT
//                       compress:EPOS2_PARAM_DEFAULT];
//
//    if (result != EPOS2_SUCCESS) {
//        [ShowMsg showErrorEpos:result method:@"addImage"];
//        return NO;
//    }
    
    result = [printer_ addPagePosition:FONT_A_WIDTH * 4 y:(PAGE_AREA_HEIGHT / 2) - (FONT_A_HEIGHT * 2)];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addPagePosition"];
        return NO;
    }
    
    result = [printer_ addTextSize:3 height:3];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addTextSize"];
        return NO;
    }
    
    result = [printer_ addTextStyle:EPOS2_PARAM_DEFAULT ul:EPOS2_PARAM_DEFAULT em:EPOS2_TRUE color:EPOS2_PARAM_DEFAULT];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addTextStyle"];
        return NO;
    }
    
    result = [printer_ addTextSmooth:EPOS2_TRUE];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addTextSmooth"];
        return NO;
    }
    
    result = [printer_ addText:@"FREE Coffee\n"];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addText"];
        return NO;
    }
    
//    result = [printer_ addPagePosition:(PAGE_AREA_WIDTH / barcodeWidth) - BARCODE_WIDTH_POS y:coffeeData.size.height + BARCODE_HEIGHT_POS];
//    if (result != EPOS2_SUCCESS) {
//        [ShowMsg showErrorEpos:result method:@"addPagePosition"];
//        return NO;
//    }
    
    result = [printer_ addBarcode:@"01234567890" type:EPOS2_BARCODE_UPC_A hri:EPOS2_PARAM_DEFAULT font: EPOS2_PARAM_DEFAULT width:barcodeWidth height:barcodeHeight];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addBarocde"];
        return NO;
    }
    
    result = [printer_ addPageEnd];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addPageEnd"];
        return NO;
    }
    
    result = [printer_ addCut:EPOS2_CUT_FEED];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"addCut"];
        return NO;
    }
    
    return YES;
}
- (void)finalizeObject
{
    if (printer_ == nil) {
        return;
    }
    
    [printer_ clearCommandBuffer];
    
    [printer_ setReceiveEventDelegate:nil];
    
    printer_ = nil;
}

- (BOOL)printData
{
    int result = EPOS2_SUCCESS;
    
    Epos2PrinterStatusInfo *status = nil;
    
    if (printer_ == nil) {
        return NO;
    }
    
    if (![self connectPrinter]) {
        return NO;
    }
    
    status = [printer_ getStatus];
//    [self dispPrinterWarnings:status];
    
    if (![self isPrintable:status]) {
        [ShowMsg show:[self makeErrorMessage:status]];
        [printer_ disconnect];
        return NO;
    }
    
    result = [printer_ sendData:EPOS2_PARAM_DEFAULT];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"sendData"];
        [printer_ disconnect];
        return NO;
    }
    
    return YES;
}
- (NSString *)makeErrorMessage:(Epos2PrinterStatusInfo *)status
{
    NSMutableString *errMsg = [[NSMutableString alloc] initWithString:@""];
    
    if (status.getOnline == EPOS2_FALSE) {
        [errMsg appendString:NSLocalizedString(@"err_offline", @"")];
    }
    if (status.getConnection == EPOS2_FALSE) {
        [errMsg appendString:NSLocalizedString(@"err_no_response", @"")];
    }
    if (status.getCoverOpen == EPOS2_TRUE) {
        [errMsg appendString:NSLocalizedString(@"err_cover_open", @"")];
    }
    if (status.getPaper == EPOS2_PAPER_EMPTY) {
        [errMsg appendString:NSLocalizedString(@"err_receipt_end", @"")];
    }
    if (status.getPaperFeed == EPOS2_TRUE || status.getPanelSwitch == EPOS2_SWITCH_ON) {
        [errMsg appendString:NSLocalizedString(@"err_paper_feed", @"")];
    }
    if (status.getErrorStatus == EPOS2_MECHANICAL_ERR || status.getErrorStatus == EPOS2_AUTOCUTTER_ERR) {
        [errMsg appendString:NSLocalizedString(@"err_autocutter", @"")];
        [errMsg appendString:NSLocalizedString(@"err_need_recover", @"")];
    }
    if (status.getErrorStatus == EPOS2_UNRECOVER_ERR) {
        [errMsg appendString:NSLocalizedString(@"err_unrecover", @"")];
    }
    
    if (status.getErrorStatus == EPOS2_AUTORECOVER_ERR) {
        if (status.getAutoRecoverError == EPOS2_HEAD_OVERHEAT) {
            [errMsg appendString:NSLocalizedString(@"err_overheat", @"")];
            [errMsg appendString:NSLocalizedString(@"err_head", @"")];
        }
        if (status.getAutoRecoverError == EPOS2_MOTOR_OVERHEAT) {
            [errMsg appendString:NSLocalizedString(@"err_overheat", @"")];
            [errMsg appendString:NSLocalizedString(@"err_motor", @"")];
        }
        if (status.getAutoRecoverError == EPOS2_BATTERY_OVERHEAT) {
            [errMsg appendString:NSLocalizedString(@"err_overheat", @"")];
            [errMsg appendString:NSLocalizedString(@"err_battery", @"")];
        }
        if (status.getAutoRecoverError == EPOS2_WRONG_PAPER) {
            [errMsg appendString:NSLocalizedString(@"err_wrong_paper", @"")];
        }
    }
    if (status.getBatteryLevel == EPOS2_BATTERY_LEVEL_0) {
        [errMsg appendString:NSLocalizedString(@"err_battery_real_end", @"")];
    }
    
    return errMsg;
}

- (BOOL)isPrintable:(Epos2PrinterStatusInfo *)status
{
    if (status == nil) {
        return NO;
    }
    
    if (status.connection == EPOS2_FALSE) {
        return NO;
    }
    else if (status.online == EPOS2_FALSE) {
        return NO;
    }
    else {
        ;//print available
    }
    
    return YES;
}
-(BOOL)connectPrinter
{
    int result = EPOS2_SUCCESS;
    
    if (printer_ == nil) {
        return NO;
    }
    
    result = [printer_ connect:connectionSting timeout:EPOS2_PARAM_DEFAULT];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"connect"];
        return NO;
    }
    
    result = [printer_ beginTransaction];
    if (result != EPOS2_SUCCESS) {
        [ShowMsg showErrorEpos:result method:@"beginTransaction"];
        [printer_ disconnect];
        return NO;
    }
    
    return YES;
}
- (void)onPtrReceive:(Epos2Printer *)printerObj code:(int)code status:(Epos2PrinterStatusInfo *)status printJobId:(NSString *)printJobId {
    
}

RCT_EXPORT_METHOD(sampleMethod:(NSString *)stringArgument numberParameter:(nonnull NSNumber *)numberArgument callback:(RCTResponseSenderBlock)callback)
{
    // TODO: Implement some actually useful functionality
    callback(@[[NSString stringWithFormat: @"numberArgument111111: %@ stringArgument: %@", numberArgument, stringArgument]]);
}

@end
