//
//  UnviredDB.m
//  RemindTrac
//
//  Created by VENKADESH on 13/06/17.
//
//

#import "UnviredDB.h"

static const NSString *DBTypeAppDb = @"AppDb";
static const NSString *DBTypeFrameworkDb = @"FrameworkDb";

@interface UnviredDB () {
    @private sqlite3 *fwDb;
    @private sqlite3 *appDb;
}
@property (nonatomic, strong)NSString *fwDbPath;
@property (nonatomic, strong)NSString *appDbPath;
@end

@implementation UnviredDB

/**
 * Checks if the database file at the given path is plaintext (unencrypted).
 * Attempts to prepare a simple statement without a key. Returns YES if it succeeds.
 */
- (BOOL)isPlainTextDatabase:(NSString *)dbPath {
    if (![[NSFileManager defaultManager] fileExistsAtPath:dbPath]) return NO;
    sqlite3 *testDb = NULL;
    int rc = sqlite3_open_v2([dbPath UTF8String], &testDb,
                             SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, NULL);
    if (rc != SQLITE_OK) {
        if (testDb) sqlite3_close(testDb);
        return NO;
    }
    sqlite3_stmt *stmt = NULL;
    rc = sqlite3_prepare_v2(testDb, "SELECT count(*) FROM sqlite_master;", -1, &stmt, NULL);
    if (stmt) sqlite3_finalize(stmt);
    sqlite3_close(testDb);
    return (rc == SQLITE_OK);
}

/**
 * Opens (or creates) a SQLite database.
 * Returns SQLITE_OK on success, or a SQLite error code.
 */
- (int)openDatabase:(sqlite3 **)db atPath:(NSString *)dbPath key:(NSString *)key error:(NSString **)errorMsg {
    if (key.length > 0 && [self isPlainTextDatabase:dbPath]) {
        // Existing DB is not encrypted, ignore the key.
        key = @"";
    }

    int rc = sqlite3_open_v2([dbPath UTF8String], db,
                             SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, NULL);
    if (rc != SQLITE_OK) {
        if (errorMsg) *errorMsg = [NSString stringWithFormat:@"%s", sqlite3_errmsg(*db)];
        return rc;
    }

    if (key.length > 0) {
        const char *cKey = [key UTF8String];
        sqlite3_key(*db, cKey, (int)strlen(cKey));
    }
    return SQLITE_OK;
}

- (void)create:(CDVInvokedUrlCommand*)command
{
    NSLog(@"OPEN FUNCTION CALLED");
    
    [self.commandDelegate runInBackground: ^{
        @try {
            CDVPluginResult *pluginResult = nil;
            
            NSDictionary *dataObjects = [command.arguments objectAtIndex:0];
            NSString *userId = dataObjects[@"userId"];
            id keyValue = dataObjects[@"encryptionKey"];
            NSString *encryptionKey = (keyValue && ![keyValue isKindOfClass:[NSNull class]]) ? (NSString *)keyValue : @"";
            NSArray *location = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *userDirectory = [location[0] stringByAppendingPathComponent:userId];
            NSFileManager *fileManager = [NSFileManager defaultManager];

            // Check if directory exists
            BOOL isDir = NO;
            if (![fileManager fileExistsAtPath:userDirectory isDirectory:&isDir] || !isDir) {
                NSError *error = nil;
                BOOL success = [fileManager createDirectoryAtPath:userDirectory
                                      withIntermediateDirectories:YES
                                                       attributes:nil
                                                            error:&error];
                if (!success) {
                  NSLog(@"Failed to create directory: %@", error.localizedDescription);
                  pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:@{@"error": error.localizedDescription}];
                  [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
                  return;
                } else {
                  NSLog(@"Directory created at path: %@", userDirectory);
                }
            } else {
                NSLog(@"Directory already exists: %@", userDirectory);
            }
            self.fwDbPath = [NSString stringWithFormat:@"%@/framework.db", userDirectory];
            NSLog(@"🔵🔵🔵 FRAMEWORK DB PATH : %@", self.fwDbPath);
            self.appDbPath = [NSString stringWithFormat:@"%@/app.db", userDirectory];
            NSLog(@"🔵🔵🔵 APP DB PATH : %@", self.appDbPath);
            
            // Close existing database connections if they are already open
            if (self->fwDb != NULL) {
                NSLog(@"Closing existing fwDb connection");
                sqlite3_close(self->fwDb);
                self->fwDb = NULL;
            }
            
            if (self->appDb != NULL) {
                NSLog(@"Closing existing appDb connection");
                sqlite3_close(self->appDb);
                self->appDb = NULL;
            }

            sqlite3_config(SQLITE_CONFIG_SERIALIZED);

            NSString *fwErrMsg = nil;
            int fwDatabaseResult = [self openDatabase:&self->fwDb atPath:self.fwDbPath key:encryptionKey error:&fwErrMsg];
            NSLog(@"FW DB RESULT:%d", fwDatabaseResult);

            if (fwDatabaseResult != SQLITE_OK) {
              NSString *errorMsg = [NSString stringWithFormat:@"Failed to open framework database: %@", fwErrMsg ?: @"Unknown error"];
              NSLog(@"%@", errorMsg);
              if (self->fwDb) {
                  sqlite3_close(self->fwDb);
                  self->fwDb = NULL;
              }
              pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:@{@"error": errorMsg}];
              [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
              return;
            }

            NSString *appErrMsg = nil;
            int appDatabaseResult = [self openDatabase:&self->appDb atPath:self.appDbPath key:encryptionKey error:&appErrMsg];
            NSLog(@"APP DB RESULT:%d", appDatabaseResult);
            if (appDatabaseResult != SQLITE_OK) {
              NSString *errorMsg = [NSString stringWithFormat:@"Failed to open app database: %@", appErrMsg ?: @"Unknown error"];
              NSLog(@"%@", errorMsg);
              if (self->fwDb) {
                  sqlite3_close(self->fwDb);
                  self->fwDb = NULL;
              }
              if (self->appDb) {
                  sqlite3_close(self->appDb);
                  self->appDb = NULL;
              }
              pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:@{@"error": errorMsg}];
              [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
              return;
            }

            NSError *error = NULL;
            
            [self executeQuery:@"PRAGMA journal_mode = WAL;" args:nil sqlDb:self->fwDb error:&error];
            [self executeQuery:@"PRAGMA read_uncommitted = 1;" args:nil sqlDb:self->fwDb error:&error];

            [self executeQuery:@"PRAGMA journal_mode = WAL;" args:nil sqlDb:self->appDb error:&error];
            [self executeQuery:@"PRAGMA foreign_keys = ON;" args:nil sqlDb:self->appDb error:&error];
            [self executeQuery:@"PRAGMA read_uncommitted = 1;" args:nil sqlDb:self->appDb error:&error];
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:true];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)execute:(CDVInvokedUrlCommand*)command {
    
    [self.commandDelegate runInBackground: ^{
        
        @try {
            
        CDVPluginResult *pluginResult = nil;
        NSError *error = NULL;
        NSArray *result = [NSArray array];
        NSDictionary *dataObjects = [command.arguments objectAtIndex:0];
        
        NSString *userId = dataObjects[@"userId"];
        NSString *dbType = dataObjects[@"dbType"];
        NSString *query = dataObjects[@"query"];
        NSArray *args = dataObjects[@"args"];
        
        sqlite3 *sql = [dbType isEqualToString:DBTypeFrameworkDb] ? self->fwDb : self->appDb;
        
        // Check if database connection is valid
        if (sql == NULL) {
            NSString *dbName = [dbType isEqualToString:DBTypeFrameworkDb] ? @"framework" : @"app";
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[NSString stringWithFormat:@"%@ database is not open. Please call create() first.", dbName]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
            return;
        }
    
//        NSLog(@"EXECUTE QUERY: %@", query);
        result = [self executeQuery:query args:args sqlDb:sql error:&error];
        if (error == NULL) {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:result];
        }
        else {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.localizedDescription];
        }
        
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
            
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = nil;
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)close:(CDVInvokedUrlCommand*)command {
    [self.commandDelegate runInBackground: ^{
        @try {
            CDVPluginResult *pluginResult = nil;
            NSError *error = NULL;
            NSFileManager *fileManager = [NSFileManager defaultManager];
            
            int fwDatabaseResult = sqlite3_close(fwDb);
            if (fwDatabaseResult == SQLITE_OK) {
                
                BOOL isFileRemoved = [fileManager removeItemAtPath:self.fwDbPath
                                                             error:&error];
                if (isFileRemoved) {
                    self->fwDb = nil;
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:nil];
                }
                else {
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:error.localizedDescription];
                }
            }
            else {
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"File does not exist."];
            }
            
            int appDatabaseResult = sqlite3_close(appDb);
            if (appDatabaseResult == SQLITE_OK) {
                BOOL isFileRemoved = [fileManager removeItemAtPath:self.appDbPath
                                                             error:&error];
                if (isFileRemoved) {
                    self->appDb = nil;
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:nil];
                }
                else {
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:error.localizedDescription];
                }
            }
            else {
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"File does not exist."];
            }
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)getDBFilePath:(CDVInvokedUrlCommand*)command {
    [self.commandDelegate runInBackground: ^{
        @try {
            NSDictionary *dataObjects = [command.arguments objectAtIndex:0];
            NSString *dbType = dataObjects[@"dbType"] != nil ? dataObjects[@"dbType"] : @"";
            NSString *dbPath = [dbType isEqualToString:DBTypeFrameworkDb] ? self.fwDbPath : self.appDbPath;
            
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:dbPath];
            if (dbPath == nil) {
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Database path not available."];
            }
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)getUserDirectoryPath:(CDVInvokedUrlCommand *)command {
    
    [self.commandDelegate runInBackground: ^{
        @try {
            NSDictionary *dataObjects = [command.arguments objectAtIndex:0];
            NSString *userId = dataObjects[@"userId"];
            
            NSArray *location = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *userDirectory = [NSString stringWithFormat:@"%@/%@/",location[0],userId];
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:userDirectory];
            if (userDirectory == nil) {
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Directory not available."];
            }
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (BOOL)executeCreate:(NSString *)sqlStatement sqlDb:(sqlite3 *)sql error:(NSError **)error {
    NSMutableString *msg = [NSMutableString stringWithFormat:@"Query : %@", sqlStatement];
    
    char *err = NULL;
    int result = sqlite3_exec(sql, [sqlStatement UTF8String], NULL, NULL, &err);
    
    if (result != SQLITE_OK) {
        // Construct an NSError
        if (error != NULL) {
            // Return a Complete Error Description.
            NSString *dbErrorDescription = [NSString stringWithFormat:@"DB Error: %@. Query: %@.", [self getSQLError:sql], sqlStatement];
            NSLog(@"UnviredDB(executeCreate:) %@ \n %@", dbErrorDescription, msg);
            *error = [NSError errorWithDomain:@"" code:0 userInfo:@{NSLocalizedDescriptionKey: dbErrorDescription}];
        }
        return NO;
    }
    return YES;
}

- (NSArray *)executeQuery:(NSString *)sqlStatement args:(NSArray *)args sqlDb:(sqlite3 *)sql error:(NSError **)error {
    
    sqlite3_stmt *statement;
    statement = [self prepareStatement:sqlStatement sqlDb:sql error:error];
    
    if (statement == NULL) {
        return NULL;
    }

    if (args && [args isKindOfClass:[NSArray class]] && [args count] > 0) {
        for (int i = 0; i < [args count]; i++) {
            id val = args[i];
            int idx = i + 1;
            if ([val isKindOfClass:[NSString class]]) {
                sqlite3_bind_text(statement, idx, [val UTF8String], -1, SQLITE_TRANSIENT);
            } else if ([val isKindOfClass:[NSNumber class]]) {
                const char *objCType = [val objCType];
                if (strcmp(objCType, @encode(double)) == 0 || strcmp(objCType, @encode(float)) == 0) {
                     sqlite3_bind_double(statement, idx, [val doubleValue]);
                } else {
                     sqlite3_bind_int64(statement, idx, [val longLongValue]);
                }
            } else if ([val isKindOfClass:[NSNull class]]) {
                sqlite3_bind_null(statement, idx);
            } else {
                 sqlite3_bind_text(statement, idx, [[NSString stringWithFormat:@"%@", val] UTF8String], -1, SQLITE_TRANSIENT);
            }
        }
    }
    
    NSLog(@"Statement: %@", sqlStatement);
    
    NSMutableArray *cursor = [NSMutableArray array];
    
    int columnCount = sqlite3_column_count(statement);
    
    if (statement) {
        while (sqlite3_step(statement) == SQLITE_ROW) {
            NSMutableDictionary *row = [NSMutableDictionary dictionary];
            for (int i = 0; i < columnCount; i++) {
                NSString *columnName = @((char *)sqlite3_column_name(statement, i));
                
                switch (sqlite3_column_type(statement, i)) {
                    case SQLITE_INTEGER:
                    {
                        row[columnName] = @((long long)sqlite3_column_int64(statement, i));
                    }
                        break;
                        
                    case SQLITE_FLOAT:
                    {
                        row[columnName] = @(sqlite3_column_double(statement, i));
                    }
                        break;
                        
                    case SQLITE_BLOB:
                    {
                        const void *blob = sqlite3_column_blob(statement, i);
                        int bytesLength = sqlite3_column_bytes(statement, i);
                        if (blob == NULL || bytesLength == 0) {
                            row[columnName] = [NSNull null];
                        } else {
                            NSData *data = [NSData dataWithBytes:blob length:bytesLength];
                            // Encode to base64 string for JSON-safe transport
                            NSString *b64 = [data respondsToSelector:@selector(base64EncodedStringWithOptions:)]
                                            ? [data base64EncodedStringWithOptions:0]
                                            : nil;
                            if (b64) {
                                row[columnName] = b64;
                            } else {
                                // Fallback: if base64 is unavailable, return hex string
                                const unsigned char *bytes = (const unsigned char *)data.bytes;
                                NSMutableString *hex = [NSMutableString stringWithCapacity:bytesLength * 2];
                                for (int j = 0; j < bytesLength; j++) {
                                    [hex appendFormat:@"%02x", bytes[j]];
                                }
                                row[columnName] = hex;
                            }
                        }
                    }
                        break;
                        
                    case SQLITE_NULL: // Bind NSNull Object to indicate that it is a NULL Object.
                    {
                        row[columnName] = [NSNull null];
                    }
                        break;
                        
                    case SQLITE_TEXT:
                    {
                        row[columnName] = @((char *)sqlite3_column_text(statement, i));
                    }
                        break;
                        
                    default:
                    {
                    }
                        break;
                }
            }
            [cursor addObject:row];
        }
        int sqlResult = sqlite3_finalize(statement);
        NSLog(@"SQL Result: %@", sqlStatement);
        if (sqlResult != SQLITE_OK) {
            // Get the Complete Error Description.
            // There is an error.
            if (error != NULL) {
                NSString *dbErrorDescription = [NSString stringWithFormat:@"DB Error: %@. Query: %@.", [self getSQLError:sql], sqlStatement];
                NSLog(@"UnviredDB(executeQuery:):%@", dbErrorDescription);
                *error = [NSError errorWithDomain:@"" code:0 userInfo:@{NSLocalizedDescriptionKey: dbErrorDescription}];
                return nil;
            }
        }
    }
    return cursor;
}

- (sqlite3_stmt *)prepareStatement:(NSString *)query sqlDb:(sqlite3 *)sql error:(NSError **)error {
    sqlite3_stmt *statement = 0X0;
    int databaseResult = sqlite3_prepare_v2(sql, [query UTF8String], -1, &statement, NULL);
    
    if (databaseResult != SQLITE_OK) {
        // Construct an NSError
        if (error != NULL) {
            NSString *dbErrorDesc = [NSString stringWithFormat:@"DB Error: %@. Query: %@", [self getSQLError:sql], query];
            NSLog(@"UnviredDB(prepareStatement:):%@", dbErrorDesc);
            *error = [NSError errorWithDomain:@"" code:0 userInfo:@{NSLocalizedDescriptionKey: dbErrorDesc}];
        }
    }
    return statement;
}

- (NSString *)getSQLError:(sqlite3 *)sql {
    return [NSString stringWithFormat:@"%s", sqlite3_errmsg(sql)];
}

- (void)saveWebDB:(CDVInvokedUrlCommand*)command {
    [self.commandDelegate runInBackground: ^{
        @try {
            [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Web DB save is only for browser."] callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)exportWebDB:(CDVInvokedUrlCommand*)command {
    [self.commandDelegate runInBackground: ^{
        @try {
            [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)deleteUserData:(CDVInvokedUrlCommand*)command {
    [self.commandDelegate runInBackground: ^{
        @try {
            NSDictionary *dataObjects = [command.arguments objectAtIndex:0];
            NSString *userId = dataObjects[@"userId"];
            NSArray *location = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *userDirectory = [location[0] stringByAppendingPathComponent:userId];
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSError *error = nil;
            BOOL exists = [fileManager fileExistsAtPath:userDirectory];
            CDVPluginResult *pluginResult = nil;
            if (!exists) {
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[NSString stringWithFormat:@"User directory does not exist: %@", userDirectory]];
            } else {
                // Close databases if open and set to nil
                if (self->appDb) {
                    int appDbCloseResult = sqlite3_close(self->appDb);
                    if (appDbCloseResult != SQLITE_OK) {
                        NSLog(@"Error closing appDb during user data deletion: %s", sqlite3_errmsg(self->appDb));
                    }
                    self->appDb = nil;
                }
                if (self->fwDb) {
                    int fwDbCloseResult = sqlite3_close(self->fwDb);
                    if (fwDbCloseResult != SQLITE_OK) {
                        NSLog(@"Error closing fwDb during user data deletion: %s", sqlite3_errmsg(self->fwDb));
                    }
                    self->fwDb = nil;
                }
                BOOL removed = [fileManager removeItemAtPath:userDirectory error:&error];
                if (removed) {
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[NSString stringWithFormat:@"User directory deleted: %@", userDirectory]];
                } else {
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[NSString stringWithFormat:@"Failed to delete user directory: %@", error.localizedDescription]];
                }
            }
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)getEncryptionKey:(CDVInvokedUrlCommand*)command {
    [self.commandDelegate runInBackground: ^{
        @try {
            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            NSString *key = [defaults stringForKey:@"unvired_db_encryption_key"];
            if (!key) {
                key = [[NSUUID UUID] UUIDString];
                [defaults setObject:key forKey:@"unvired_db_encryption_key"];
                [defaults synchronize];
            }
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:key];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } @catch (NSException *exception) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception description]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

@end
