//
//  Authentication.m
//  rainbow
//  Created by Doha Tubaileh on 8/13/19.
//  Copyright © 2019 Facebook. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import "Authentication.h"
#import <React/RCTLog.h>
#import "Rainbow/Rainbow.h"
#import "RNRainbowRn.h"
#import "IEventEmmiter.h"
#import "Contact+DictRepresentation.h"
#import "AuthenticationEventsNames.h"
#import <Rainbow/NSError+Details.h>
#import "MyUser+DictRepresentation.h"

@interface Authentication ()
@property (strong, nonatomic, readonly) NSString *AUTHENTICATION_RESULT_EVENT_NAME;
@property (strong, nonatomic , readonly) NSString *SINGOUT_RESULT_EVENT_NAME;
@property (nonatomic) BOOL loginSuccess;
@property (strong, nonatomic) NSString *serverName;
@property (strong, nonatomic) MyUser *myUser;
@property (strong, nonatomic) IEventEmmiter *eventEmitter;
@end

@implementation Authentication
RCT_EXPORT_MODULE();

- (instancetype)init {
    self = [super init];
    if (self) {
        NSLog(@"Authentication module initialized");
        //do any init here
        [self registerAuthEvents];
        _loginSuccess = NO;
        _myUser = [ServicesManager sharedInstance].myUser;
        _serverName =[ _myUser.server serverDisplayedName];

    }
    return self;
}

- (void)dealloc {
    [self unRegisterAuthEvents];
    //Each event you send it from ios to react native, you must count them and
}

#pragma mark - ReactNative_functions

RCT_EXPORT_METHOD(silentLogin) {
    NSLog(@"[Authentication] silentLogin");
    [ self onAuthenticationStart];
    if ([[[ServicesManager sharedInstance] myUser]contact] == nil) {
        NSLog(@"No saved user");
        _loginSuccess = NO;
        [self emitError:AuthenticationResult errorCode:@""];
        return;
    }
    NSLog(@"[Authentication] my user name: %@",[[[ServicesManager sharedInstance] myUser]contact].fullName);
    [self login:[[ServicesManager sharedInstance] myUser].username password:[[ServicesManager sharedInstance] myUser].password];
}

RCT_EXPORT_METHOD(registerByEmail: (NSString*)email){
    NSLog(@"[Authentication] registerByEmail");
    IEventEmmiter *eventEmitter = [self eventEmitter];

    [[ServicesManager sharedInstance].loginManager sendNotificationForEnrollmentTo:email completionHandler:^(NSDictionary * _Nullable jsonResponse, NSError * _Nullable error) {
        if(error){
            NSLog(@"[Authentication] registerByEmail : Failed to send registration email,%@ ", error);
            [eventEmitter sendEvent:OnSendCodeComplete eventBody:(error.errorMessage ?: @"Unknown error")];
        } else{
            NSLog(@"[Authentication] registerByEmail : registration email sent sucessfully  ");

            [eventEmitter sendEvent:OnSendCodeComplete eventBody:@YES];
        }
    }];
    
}

RCT_EXPORT_METHOD(validateRegistrationToken:(NSDictionary *)params){
        NSString *temporaryCode = params[@"verificationCode"] ?: @"";
        NSString *email = params[@"email"] ?: @"";
        NSString *password = params[@"password"] ?: @"";

        NSLog(@"[Authentication] validateRegistrationToken");
    IEventEmmiter *eventEmitter = [self eventEmitter];

    [[ServicesManager sharedInstance].loginManager sendSelfRegisterRequestWithLoginEmail:email password:password temporaryCode:temporaryCode completionHandler:^(NSDictionary * _Nullable jsonResponse, NSError * _Nullable error) {
        
        if (error) {
            NSString *errorMessage = error.localizedDescription ?: @"Unknown error";
            NSLog(@"[Authentication] validateRegistrationToken failure %@", errorMessage);
            
            NSDictionary *payload = @{
                @"success": @(NO),
                @"message": errorMessage
            };


            [eventEmitter sendEvent:OnValidationToken eventBody:payload];
        } else {
            NSLog(@"[Authentication] validateRegistrationToken success");
            NSDictionary *payload = @{
                @"success": @(YES),
                @"message": @""
            };

            [eventEmitter sendEvent:OnValidationToken eventBody:payload];
        }
    } ];
}


RCT_EXPORT_METHOD(login :(NSString*)email password:(NSString*)password) {
    NSLog(@"[Authentication] login: %@ ",email );
    IEventEmmiter *eventEmitter = [self eventEmitter];
    [self onAuthenticationStart];
    BOOL autoLogin = [[ServicesManager sharedInstance] loginManager].autoLogin;
    if( autoLogin == YES && [[[ServicesManager sharedInstance] myUser]contact].fullName != nil ){
        NSLog(@"[Authentication] Authentication Succeeded already connected ");
        _loginSuccess = YES;
        //make connect to the SDK , so you can listen to the SDK events
        [[ServicesManager sharedInstance].loginManager connect];
        NSMutableDictionary *message = [NSMutableDictionary dictionary];
        [message setObject: _myUser.myUserDictionaryRepresentation forKey:@"user"];
        if (eventEmitter) {
            [eventEmitter sendEvent:AuthenticationResult eventBody:message];
          } else {
            NSLog(@"[Authentication] login : Failed to get MyEventEmitter instance.");
          }
        return;
    }
    [self startConnection:email password:password];
}

RCT_EXPORT_METHOD(signOut) {
    NSLog(@"[Authentication] signOut" );
    [[[ServicesManager sharedInstance] loginManager] disconnect];
    [[[ServicesManager sharedInstance] loginManager] resetAllCredentials];
}

RCT_EXPORT_METHOD(checkNetworkConnection) {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didupdateConnectionState:) name:kLoginManagerDidLostConnection object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didupdateConnectionState:) name:kLoginManagerDidReconnect object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didupdateConnectionState:) name:kServicesManagerNetworkConnectionDetected object:nil];
}


#pragma mark - Auth_Notifications

-(void) didLogin:(NSNotification *) notification {
    IEventEmmiter *eventEmitter = [self eventEmitter];

    NSLog(@"[Authentication] didLogin connection was Succeeded");
    _loginSuccess = YES;
    [self onAuthenticationComplete:YES];
    NSMutableDictionary *message = [NSMutableDictionary dictionary];
    [message setObject:_myUser.myUserDictionaryRepresentation forKey:@"user"];
    if (eventEmitter) {
        [eventEmitter sendEvent:AuthenticationResult eventBody:message];
      } else {
        NSLog(@"[Authentication] login : Failed to get MyEventEmitter instance.");
      }

}

-(void) didLogout:(NSNotification *) notification {
    NSLog(@"[Authentication] ConnectedUser signOut ");
    NSError *error = (NSError *) notification.object;

    IEventEmmiter *eventEmitter = [self eventEmitter];
    _loginSuccess = NO;
    if (eventEmitter) {
        [eventEmitter sendEvent:CurrentUserSignedOut eventBody:@""];
      } else {
        NSLog(@"[Authentication] login : Failed to get MyEventEmitter instance.");
      }

}

-(void)failedToAuthenticate:(NSNotification *) notification {
    NSError *error = (NSError *) notification.object;
    NSString *errorMessage = error? [self reactAuthErrorConverter:error.code]:@"Could not read server answer";
    NSLog(@"[Authentication] failedToAuthenticate: %@ , %@",error.localizedDescription , errorMessage);
    [self emitError:AuthenticationResult errorCode:errorMessage];
}

-(void) didChangeUser:(NSNotification *) notification {
    if(![NSThread isMainThread]){
        dispatch_async(dispatch_get_main_queue(), ^{
            [self didChangeUser:notification];
        });
        return;
    }
    NSLog(@"[Authentication] didChangeUser");
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
}

-(void) didupdateConnectionState:(NSNotification *) notification {
    IEventEmmiter *eventEmitter = [self eventEmitter];
    BOOL isNetworkDisconnected = [ServicesManager sharedInstance].isNetworkDisconnected;
    NSLog(@"[Authentication] didupdateConnectionState %@", @(isNetworkDisconnected));

    if (eventEmitter) {
        [eventEmitter sendEvent:IsNetworkAvailable eventBody:[NSNumber numberWithBool:!isNetworkDisconnected]];
      } else {
        NSLog(@"[Authentication] login : Failed to get MyEventEmitter instance.");
      }
}



#pragma mark - Others

-(void)startConnection:(NSString*)email password : (NSString*)password {
    NSLog(@"[Authentication] startConnection");
    if(_serverName){
        [[NSNotificationCenter defaultCenter] postNotificationName:kLoginManagerDidChangeServer object:@{ @"serverURL": _serverName}];
    }
    [[ServicesManager sharedInstance].loginManager setUsername:email andPassword:password];
    [[ServicesManager sharedInstance].loginManager connect];
}


-(void)emitError :(NSString*)eventName errorCode:(NSString*)errorCode {
    NSLog(@"[Authentication] emitError %@", eventName);
    IEventEmmiter *eventEmitter = [self eventEmitter];
    [self onAuthenticationComplete:NO];
    _loginSuccess = NO;
    NSMutableDictionary *message = [NSMutableDictionary dictionary];
    [message setObject:errorCode forKey:@"errorCode"];
    if (eventEmitter) {
        [eventEmitter sendEvent:eventName eventBody:message];
      } else {
        NSLog(@"[Authentication] login : Failed to get MyEventEmitter instance.");
      }
}

-(NSString *) reactAuthErrorConverter :(NSInteger) errorDescription {
    BOOL isNetworkDisconnected = [ServicesManager sharedInstance].isNetworkDisconnected;
    if (isNetworkDisconnected) {
        return NO_NETWORK_CONNECTION;
    }
    else {
        switch (errorDescription) {
            case 401500:
                NSLog(@"");
                return CONNECTION_WRONG_LOGIN_OR_PWD;
                
            case 401501:
                return CONNECTION_ACCOUNT_LOCKED;
                
            case 401520:
                return CONNECTION_ACCOUNT_NOT_ACTIVATE;
                
            case 401521:
                return CONNECTION_COMPANY_NOT_ACTIVATE;
                
            case 403020:
                return TOO_OLD_CLIENT;
                
            default:
                return CONNECTION_ERROR;
                break;
        }
    }
    
}
- (void)onAuthenticationStart {
    IEventEmmiter *eventEmitter = [self eventEmitter];
    if (eventEmitter) {
        [eventEmitter sendEvent:AuthStateChange eventBody:@{@"inProgress": @(YES)}];
        
      } else {
        NSLog(@"[Authentication] login : Failed to get MyEventEmitter instance.");
      }
}

- (void)onAuthenticationComplete:(BOOL)success {
    IEventEmmiter *eventEmitter = [self eventEmitter];
    if (eventEmitter) {
        [eventEmitter sendEvent:AuthStateChange eventBody:@{@"inProgress": @(NO),    @"error": @(!success)
}];
        
      } else {
        NSLog(@"[Authentication] login : Failed to get MyEventEmitter instance.");
      }
}

-(void)registerAuthEvents{
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didLogin:) name:kLoginManagerDidLoginSucceeded object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(failedToAuthenticate:) name:kLoginManagerDidFailedToAuthenticate object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didLogout:) name:kLoginManagerDidLogoutSucceeded object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeUser:) name:kLoginManagerDidChangeUser object:nil];
}

-(void)unRegisterAuthEvents{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kLoginManagerDidLoginSucceeded object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kLoginManagerDidFailedToAuthenticate object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kLoginManagerDidLogoutSucceeded object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kLoginManagerDidChangeUser object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kLoginManagerDidLostConnection object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kLoginManagerDidReconnect object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kServicesManagerNetworkConnectionDetected object:nil];
}
+ (BOOL)requiresMainQueueSetup
{
    return YES;
}
- ( IEventEmmiter *)eventEmitter {
    if (!_eventEmitter) {
        _eventEmitter = [self.bridge moduleForClass:[IEventEmmiter class]];
    }
    return _eventEmitter;
}
@end

