  #import <Foundation/Foundation.h>

#import <SGSBase/SGSBase.h>
#import <SGSAuth/SGSAuth.h>

#import "AuthNativeInterface.h"

// MARK: - PlaytimeNotification

@interface SGSPlaytimeNotification : NSObject
@property (copy) NSString *identifier;
+ (SGSPlaytimeNotification *)sharedInstance;
@end

@implementation SGSPlaytimeNotification
+ (SGSPlaytimeNotification *)sharedInstance {
    static SGSPlaytimeNotification *notification;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ notification = [[SGSPlaytimeNotification alloc] init]; });
    return notification;
}
- (void)playtimeDidUpdate:(NSNotification *)notification {
    NSString *message = [notification.userInfo objectForKey:SGSPlaytimeNotificationKeys.message];
    NSDictionary *resultDic = @{ @"message": message ?: @"" };
    StoveSDKNativeNotifyPayload *payload =
        [StoveSDKNativeNotifyPayload notifyWithIdentifier:self.identifier value:resultDic];
    [payload notifyMessage];
}
@end

// MARK: - Extern APIs

void stove_auth_initialize(const char* identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    [SGSAuth initializeWithCompletionHandler:^(SGSResult * _Nonnull result) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_initialize_version(const char *version, const char *identifier)
{
    NSString *nsVersion = StoveSDKMakeNSString(version);
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    [SGSAuth initializeWithVersion:nsVersion
                 completionHandler:^(SGSResult * _Nonnull result) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_login(const char *providerClassName, const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    NSString *nsProviderClassName = StoveSDKMakeNSString(providerClassName);
    
    Class providerClass = NSClassFromString(nsProviderClassName);
    id provider = [[providerClass alloc] init];
    
    [SGSAuth loginWithProvider:provider
            fromViewController:nil
             completionHandler:^(SGSResult * _Nonnull result, SGSAccessToken * _Nullable accessToken) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   [accessToken dictionary], @"accessToken",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }]; 
}

void stove_auth_loginGeneric(const char *providerClassName, const char *userDicString, const char *identifier)
{
    NSString *nsProviderClassName = StoveSDKMakeNSString(providerClassName);
    NSString *nsUserDicString = StoveSDKMakeNSString(userDicString);
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    Class providerClass = NSClassFromString(nsProviderClassName);
    id<SGSAuthProviderProtocol> provider = [[providerClass alloc] init];
    provider.user = [nsUserDicString JSONObject];
    
    [SGSAuth loginWithProvider:provider
            fromViewController:nil
             completionHandler:^(SGSResult * _Nonnull result, SGSAccessToken * _Nullable accessToken) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   [accessToken dictionary], @"accessToken",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_loginGeneral(const char *providerClassName, const char *userDicString, const char *identifier)
{
}

void stove_auth_register(const char *providerClassName, const char *termsOfServiceDataListString, const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    NSString *nsTermsOfServiceDataListString = StoveSDKMakeNSString(termsOfServiceDataListString);
    NSString *nsProviderClassName = StoveSDKMakeNSString(providerClassName);
    
    NSMutableArray *termsOfServiceDataArray = [NSMutableArray array];
    NSArray *termsOfServiceDataList = [nsTermsOfServiceDataListString JSONObject];
    
    for (NSDictionary *termsOfServiceData in termsOfServiceDataList) {
        [termsOfServiceDataArray addObject:[SGSTermsOfServiceData termsOfServiceDataWithDictionary:termsOfServiceData]];
    }
    
    Class providerClass = NSClassFromString(nsProviderClassName);
    id provider = [[providerClass alloc] init];
    
    [SGSAuth registerWithProvider:provider
               fromViewController:nil
               termsOfServiceData:termsOfServiceDataArray
                completionHandler:^(SGSResult * _Nonnull result, SGSAccessToken * _Nullable accessToken) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   [accessToken dictionary], @"accessToken",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_registerGeneric(const char *providerClassName, const char *userDicString, const char *termsOfServiceDataListString, const char *identifier)
{
    NSString *nsProviderClassName = StoveSDKMakeNSString(providerClassName);
    NSString *nsUserDicString = StoveSDKMakeNSString(userDicString);
    NSString *nsTermsOfServiceDataListString = StoveSDKMakeNSString(termsOfServiceDataListString);
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    Class providerClass = NSClassFromString(nsProviderClassName);
    id<SGSAuthProviderProtocol> provider = [[providerClass alloc] init];
    provider.user = [nsUserDicString JSONObject];
    
    NSMutableArray *termsOfServiceDataArray = [NSMutableArray array];
    NSArray *termsOfServiceDataList = [nsTermsOfServiceDataListString JSONObject];
    
    for (NSDictionary *termsOfServiceData in termsOfServiceDataList) {
        [termsOfServiceDataArray addObject:[SGSTermsOfServiceData termsOfServiceDataWithDictionary:termsOfServiceData]];
    }
    
    [SGSAuth registerWithProvider:provider
               fromViewController:nil
               termsOfServiceData:termsOfServiceDataArray
                completionHandler:^(SGSResult * _Nonnull result, SGSAccessToken * _Nullable accessToken) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   [accessToken dictionary], @"accessToken",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_logout()
{
    [SGSAuth logout];
}

const char *stove_auth_accessToken()
{
    NSDictionary *accessTokenDic = [[SGSAuth accessToken] dictionary];
    NSString *accessTokenJSONStr = [accessTokenDic JSONString];
    
    return StoveSDKMakeCString(accessTokenJSONStr);
}



void stove_auth_setAccessToken(const char *accessTokenString)
{
    NSString *nsAccessTokenString = StoveSDKMakeNSString(accessTokenString);
    
    if (!isNilOrEmpty(nsAccessTokenString)) {
        SGSAccessToken *accessToken = [SGSAccessToken accessTokenWithDictionary:[nsAccessTokenString JSONObject]];
        [SGSAuth setAccessToken:accessToken];
    }
}

void stove_auth_fetch(const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    [SGSTermsOfService fetchWithCompletionHandler:^(SGSResult * _Nonnull result, NSArray<SGSTermsOfServiceData *> * _Nullable termsOfServiceData) {
        
        NSMutableArray *agreedTermsOfServiceDataList = [NSMutableArray array];
        for (SGSTermsOfServiceData *terms in termsOfServiceData) {
            [agreedTermsOfServiceDataList addObject:[terms dictionary]];
        }
        
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   agreedTermsOfServiceDataList, @"termsOfServiceDataList",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_fetchForRegister(const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    [SGSTermsOfService fetchForRegisterWithCompletionHandler:^(SGSResult * _Nonnull result, NSArray<SGSTermsOfServiceData *> * _Nullable termsOfServiceData) {
        
        NSMutableArray *agreedTermsOfServiceDataList = [NSMutableArray array];
        for (SGSTermsOfServiceData *terms in termsOfServiceData) {
            [agreedTermsOfServiceDataList addObject:[terms dictionary]];
        }
        
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   agreedTermsOfServiceDataList, @"termsOfServiceDataList",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_save(const char *termsOfServiceDataListString, const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    NSString *nsTermsOfServiceDataListString = StoveSDKMakeNSString(termsOfServiceDataListString);
    
    NSMutableArray *termsOfServiceDataArray = [NSMutableArray array];
    NSArray *termsOfServiceDataList = [nsTermsOfServiceDataListString JSONObject];
    
    for (NSDictionary *termsOfServiceData in termsOfServiceDataList) {
        [termsOfServiceDataArray addObject:[SGSTermsOfServiceData termsOfServiceDataWithDictionary:termsOfServiceData]];
    }
    
    [SGSTermsOfService saveWithTermsOfServiceData:termsOfServiceDataArray completionHandler:^(SGSResult * _Nonnull result) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_refresh(const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    [[SGSAuth accessToken] refreshWithCompletionHandler:^(SGSResult * _Nonnull result) {
        
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_link(const char *providerClassName, const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    NSString *nsProviderClassName = StoveSDKMakeNSString(providerClassName);
    
    Class providerClass = NSClassFromString(nsProviderClassName);
    id provider = [[providerClass alloc] init];
    
    [[[SGSAuth accessToken] user] linkWithProvider:provider
                                fromViewController:nil
                                 completionHandler:^(SGSResult * _Nonnull result) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_linkGeneric(const char *providerClassName, const char *userDicString, const char *identifier)
{
    NSString *nsProviderClassName = StoveSDKMakeNSString(providerClassName);
    NSString *nsUserDicString = StoveSDKMakeNSString(userDicString);
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    Class providerClass = NSClassFromString(nsProviderClassName);
    id<SGSAuthProviderProtocol> provider = [[providerClass alloc] init];
    provider.user = [nsUserDicString JSONObject];
    
    [[[SGSAuth accessToken] user] linkWithProvider:provider
                                fromViewController:nil
                                 completionHandler:^(SGSResult * _Nonnull result) {
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_linkGeneral(const char *providerClassName, const char *jsonString, const char *identifier)
{

}

void stove_auth_fetchOperation(const char *identifier)
{
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    
    [SGSOperation fetchWithCompletionHandler:^(SGSResult * _Nonnull result) {
        
        NSDictionary *resultDic = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [result dictionary], @"result",
                                   nil];
        
        StoveSDKNativeCallbackPayload *payload =
        [StoveSDKNativeCallbackPayload payloadWithIdentifier:nsIdentifier value:resultDic];
        [payload sendMessage];
    }];
}

void stove_auth_setGameProfile(const char *gameProfile)
{
    NSString *nsGameProfile = StoveSDKMakeNSString(gameProfile);
    
    if (!isNilOrEmpty(nsGameProfile)) {
        [[SGSAuth accessToken] user].gameProfile = [SGSGameProfile gameProfileWithDictionary:[nsGameProfile JSONObject]];
    } else {
        [[SGSAuth accessToken] user].gameProfile = nil;
    }
}

void stove_auth_setGameProfileProperties(const char *properties)
{
    NSString *nsProperties = StoveSDKMakeNSString(properties);
    
    if (!isNilOrEmpty(nsProperties)) {
        [[[SGSAuth accessToken] user] gameProfile].properties = [nsProperties JSONObject];
    } else {
        [[[SGSAuth accessToken] user] gameProfile].properties = [NSMutableDictionary dictionary];
    }
}

const char *stove_auth_version() {
    NSString * version = [SGSAuth moduleVersion];
    return StoveSDKMakeCString(version);
}

bool stove_auth_is_main(const char *providerCode) {
    NSString *nsProviderCode = StoveSDKMakeNSString(providerCode);
    for (SGSProviderUser* providerUser in [[[SGSAuth accessToken] user] providerUsers]) {
        if ([providerUser.code isEqual: nsProviderCode]) {
            if (providerUser.isMain) {
                return true;
            }
        }
    }
    return false;
}

void stove_auth_setPlaytimeListener(const char *identifier) {
    NSString *nsIdentifier = StoveSDKMakeNSString(identifier);
    [[SGSPlaytimeNotification sharedInstance] setIdentifier:nsIdentifier];
    [[NSNotificationCenter defaultCenter] removeObserver:[SGSPlaytimeNotification sharedInstance]
                                                    name:NSNotification.SGSPlaytimeDidUpdateNotification
                                                  object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:[SGSPlaytimeNotification sharedInstance]
                                             selector:@selector(playtimeDidUpdate:)
                                                 name:NSNotification.SGSPlaytimeDidUpdateNotification
                                               object:nil];
}

