//
//  InMobiInterface.m
//  Unity-iPhone
//
//  Created by Vineet Srivastava on 11/22/16.
//
//

#import <Foundation/Foundation.h>
#import "USDKCommonTypes.h"
#import "InMobiBanner.h"
#import "InMobiInterstitial.h"
#import "InMobiUnifiedIdService.h"
#import <InMobiSDK/InMobiSDK.h>"
#include "InMobiObjectCache.h"
#import "InMobiPlugin.h"

/// Returns an NSString copying the characters from |bytes|, a C array of UTF8-encoded bytes.
/// Returns nil if |bytes| is NULL.
static NSString *InMobiStringFromUTF8String(const char *bytes) { return bytes ? @(bytes) : nil; }

static NSDictionary *InMobiDictionaryFromJsonString(const char *bytes) {
    NSString *jsonStr = InMobiStringFromUTF8String(bytes);
    NSData *jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
    NSError *error;
    NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error];
    return jsonDic;
}

static IMUserDataModel *InMobiUnifiedIdModelFromJson(const char *jsonString) {
    NSDictionary *jsonDic = InMobiDictionaryFromJsonString(jsonString);
    
    NSLog(@"InMobiUnifiedIdModelFromJson called");
    
    NSString *Pmd5 = jsonDic[@"phoneNumberMD5"];
    NSString *Psha1 = jsonDic[@"phoneNumberSHA1"];
    NSString *Psha256 = jsonDic[@"phoneNumberSHA256"];

    NSString *Emd5 = jsonDic[@"emailIdMD5"];
    NSString *Esha1 = jsonDic[@"emailIdSHA1"];
    NSString *Esha256 = jsonDic[@"emailIdSHA256"];

    NSDictionary *extras = jsonDic[@"extras"];

    IMUserDataTypes *phoneNumber = [[IMUserDataTypes alloc] initWithMd5:Pmd5 sha1:Psha1 sha256:Psha256];
    IMUserDataTypes *emailId = [[IMUserDataTypes alloc] initWithMd5:Emd5 sha1:Esha1 sha256:Esha256];
    IMUserDataModel *unifiedIdDatamodel = [[IMUserDataModel alloc] initWithPhoneNumber:phoneNumber emailId:emailId extras:extras];

    return unifiedIdDatamodel;


}

/// Returns a C string from a C array of UTF8-encoded bytes.
static const char *cStringCopy(const char *string) {
    if (!string) {
        return NULL;
    }
    char *res = (char *)malloc(strlen(string) + 1);
    strcpy(res, string);
    return res;
}

/// Returns a C string from a C array of UTF8-encoded bytes.
static const char **cStringArrayCopy(NSArray *array) {
    if (array == nil) {
        return nil;
    }
    
    const char **stringArray;
    
    stringArray = malloc(array.count * sizeof(char *));
    for (int i = 0; i < array.count; i++) {
        stringArray[i] = cStringCopy([array[i] UTF8String]);
    }
    return stringArray;
}

#pragma InMobi SDK APIs
const char* Init(const char* accountId){
    NSLog(@"InMobi SDK initialized called");
    NSString *error = [InMobiPlugin checkIfIMSDKInitilisationCanBeProceeded:InMobiStringFromUTF8String(accountId)];
    
    if (error) {
        NSLog(error);
        return cStringCopy(error.UTF8String);
    }
    
    [IMSdk initWithAccountID:InMobiStringFromUTF8String(accountId)
        andCompletionHandler:nil];
    return NULL;
}

const char *InitwithGDPRConsent(const char* accountId, const char* gdprConsentObject){
    NSLog(@"InMobi SDK initialized called");
    NSString *error = [InMobiPlugin checkIfIMSDKInitilisationCanBeProceeded:InMobiStringFromUTF8String(accountId)];
    
    if (error) {
        NSLog(error);
        return cStringCopy(error.UTF8String);
    }
    
    [IMSdk initWithAccountID:InMobiStringFromUTF8String(accountId)
           consentDictionary:InMobiDictionaryFromJsonString(gdprConsentObject)
        andCompletionHandler:nil];
    return NULL;
}

void UpdateGdprConsentObject(const char* gdprConsentObject) {
    NSLog(@"UpdateGdprConsentObject called");
    [IMSdk updateGDPRConsent:InMobiDictionaryFromJsonString(gdprConsentObject)];
}

/// Unified Id method
void SetPublisherProvidedUnifiedId(const char* unifiedIdObject) {
    NSLog(@"UpdateGdprConsentObject called");
    [IMSdk setPublisherProvidedUnifiedId:InMobiDictionaryFromJsonString(unifiedIdObject)];
}

void SetLogLevel(const char* logLevel){
    NSString *level = InMobiStringFromUTF8String(logLevel);
    if(level){
        if([level isEqualToString:@"None"]){
            [IMSdk setLogLevel:kIMSDKLogLevelNone];
        }
        else if ([level isEqualToString:@"Debug"]){
            [IMSdk setLogLevel:kIMSDKLogLevelDebug];
        }
        else if ([level isEqualToString:@"Error"]){
            [IMSdk setLogLevel:kIMSDKLogLevelError];
        }
    }
}

void SetAge(int age){
    [IMSdk setAge:age];
}

void SetAgeGroup(const char* ageGroup){
    NSString *ageGroupType = InMobiStringFromUTF8String(ageGroup);
    if (ageGroupType) {
        if ([ageGroupType isEqualToString:@"Below18"]) {
            [IMSdk setAgeGroup:kIMSDKAgeGroupBelow18];
        }
        else if ([ageGroupType isEqualToString:@"Between18And24"]) {
            [IMSdk setAgeGroup:kIMSDKAgeGroupBetween18And24];
        }
        else if ([ageGroupType isEqualToString:@"Between25And29"]){
            [IMSdk setAgeGroup:kIMSDKAgeGroupBetween25And29];
        }
        else if ([ageGroupType isEqualToString:@"Between30And34"]){
            [IMSdk setAgeGroup:kIMSDKAgeGroupBetween30And34];
        }
        else if ([ageGroupType isEqualToString:@"Between35To44"]){
            [IMSdk setAgeGroup:kIMSDKAgeGroupBetween35And44];
        }
        else if ([ageGroupType isEqualToString:@"Between45To54"]){
            [IMSdk setAgeGroup:kIMSDKAgeGroupBetween45And54];
        }
        else if ([ageGroupType isEqualToString:@"Between55To65"]){
            [IMSdk setAgeGroup:kIMSDKAgeGroupBetween55And65];
        }
        else if ([ageGroupType isEqualToString:@"Above65"]){
            [IMSdk setAgeGroup:kIMSDKAgeGroupAbove65];
        }
    }
}

void SetAreaCode(const char* areaCode){
    [IMSdk setAreaCode:InMobiStringFromUTF8String(areaCode)];
}

void SetPostalCode(const char* postalCode){
    [IMSdk setPostalCode:InMobiStringFromUTF8String(postalCode)];
}

void SetLocationWithCityStateCountry(const char* city, const char* state, const char* country){
    [IMSdk setLocationWithCity:InMobiStringFromUTF8String(city) state:InMobiStringFromUTF8String(state) country:InMobiStringFromUTF8String(country)];
}

void SetYearOfBirth(int yearOfBirth){
    [IMSdk setYearOfBirth:(NSInteger)yearOfBirth];
}

void SetGender(const char* gender){
    NSString* genderType = InMobiStringFromUTF8String(gender);
    if (genderType) {
        if ([genderType isEqualToString:@"GENDER_FEMALE"]) {
            [IMSdk setGender:kIMSDKGenderFemale];
        } else if ([genderType isEqualToString:@"GENDER_MALE"]) {
            [IMSdk setGender:kIMSDKGenderMale];
        }
    }
}

void SetEducation(const char* educationType){
    NSString* education = InMobiStringFromUTF8String(educationType);
    if (education) {
        if ([education isEqualToString:@"EDUCATION_HIGHSCHOOLORLESS"]) {
            [IMSdk setEducation:kIMSDKEducationHighSchoolOrLess];
        } else if ([education isEqualToString:@"EDUCATION_COLLEGEORGRADUATE"]) {
            [IMSdk setEducation:kIMSDKEducationCollegeOrGraduate];
        } else if ([education isEqualToString:@"EDUCATION_POSTGRADUATEORABOVE"]) {
            [IMSdk setEducation:kIMSDKEducationPostGraduateOrAbove];
        }
    }
}

void SetLanguage(const char* language){
    [IMSdk setLanguage:InMobiStringFromUTF8String(language)];
}

void SetInterests(const char* interests){
    [IMSdk setInterests:InMobiStringFromUTF8String(interests)];
}

#pragma End of InMobi SDK APIS

#pragma Start InMobiBanner APIs
/// Creates a GADBannerView with the specified width, height, and position. Returns a reference to
/// the GADUBannerView.
InMobiBannerRef InMobiCreateBannerAd(InMobiBannerClientRef *bannerClient, const char *placementId,
                                     int width, int height, int position) {
    InMobiBanner *banner = [[InMobiBanner alloc] initBannerAd:bannerClient
                                                  placementId:InMobiStringFromUTF8String(placementId)
                                                        width:width
                                                       height:height
                                                     position:position];
    
    InMobiObjectCache *cache = [InMobiObjectCache sharedInstance];
    [cache.references setObject:banner forKey:[banner inmobi_referenceKey]];
    return (__bridge InMobiBannerRef)banner;
}

void SetBannerKeyWords(InMobiBannerRef banner, const char *keywords){
    InMobiBanner *internalBanner = (__bridge InMobiBanner *)banner;
    [internalBanner setKeywords:InMobiStringFromUTF8String(keywords)];
}

void SetBannerEnableAutoRefresh(InMobiBannerRef banner, bool flag){
    InMobiBanner *internalBanner = (__bridge InMobiBanner *)banner;
    [internalBanner setEnableAutoRefresh:flag];
}

void SetBannerRefreshInterval(InMobiBannerRef banner, int refreshInterval){
    InMobiBanner *internalBanner = (__bridge InMobiBanner *)banner;
    [internalBanner setRefreshInterval:refreshInterval];
}

void LoadBannerAd(InMobiBannerRef banner){
    InMobiBanner *internalBanner = (__bridge InMobiBanner *)banner;
    [internalBanner loadAd];
}

void DestroyBannerAd(InMobiBannerRef banner){
    InMobiBanner *internalBanner = (__bridge InMobiBanner *)banner;
    [internalBanner destroy];
}

///Sets the banner callbacks to be invoked durin banner ad events
void SetBannerCallbacks(InMobiBannerRef banner,
                        InMobiBannerOnAdLoadSucceeded onAdLoadSucceeded,
                        InMobiBannerOnAdLoadFailed onAdLoadFailed,
                        InMobiBannerOnAdDisplayed onAdDisplayed,
                        InMobiBannerOnAdDismissed onAdDismissed,
                        InMobiBannerOnAdInteraction onAdInteraction,
                        InMobiBannerOnUserLeftApplication onUserLeftApplication,
                        InMobiBannerOnAdRewardActionCompleted onAdRewardActionCompleted){
    InMobiBanner *internalBanner = (__bridge InMobiBanner *)banner;
    internalBanner.onAdLoadSucceeded = onAdLoadSucceeded ;
    internalBanner.onAdLoadFailed = onAdLoadFailed;
    internalBanner.onAdDisplayed = onAdDisplayed;
    internalBanner.onAdDismissed = onAdDismissed;
    internalBanner.onAdInteraction = onAdInteraction;
    internalBanner.onUserLeftApplication = onUserLeftApplication;
    internalBanner.onAdRewardActionCompleted = onAdRewardActionCompleted;
}
#pragma End InMobiBanner APIs

#pragma InmobiInterstitial APIs
InMobiInterstitialRef InMobiCreateInterstitialAd(InMobiInterstitialClientRef *interstitialClient,
                                                 const char* placementId)
{
    InMobiInterstitial *interstital = [[InMobiInterstitial alloc] initInterstitialAd:interstitialClient
                                                                         placementId:InMobiStringFromUTF8String(placementId)];
    InMobiObjectCache *cache = [InMobiObjectCache sharedInstance];
    [cache.references setObject:interstital forKey:[interstital inmobi_referenceKey]];
    return (__bridge InMobiInterstitialRef)interstital;
}

void SetInterstitialKeyWords(InMobiInterstitialRef interstitial, const char *keywords){
    InMobiInterstitial *internalInterstitial = (__bridge InMobiInterstitial *)interstitial;
    [internalInterstitial setKeywords:InMobiStringFromUTF8String(keywords)];
}

void LoadInterstitialAd(InMobiInterstitialRef interstitial){
    InMobiInterstitial *internalInterstitial = (__bridge InMobiInterstitial *)interstitial;
    [internalInterstitial loadAd];
}

bool IsInterstitialAdReady(InMobiInterstitialRef interstitial)
{
    InMobiInterstitial *internalInterstitial = (__bridge InMobiInterstitial *)interstitial;
    return [internalInterstitial isReady];
}

void ShowInterstitialAd(InMobiInterstitialRef interstitial){
    InMobiInterstitial *internalInterstitial = (__bridge InMobiInterstitial *)interstitial;
    [internalInterstitial showAd];
}

///Sets the banner callbacks to be invoked durin banner ad events
void SetInterstitialCallbacks(InMobiInterstitialRef interstitial,
                              InMobiInterstitialOnAdReceived onAdReceived,
                              InMobiInterstitialOnAdLoadSucceeded onAdLoadSucceeded,
                              InMobiInterstitialOnAdLoadFailed onAdLoadFailed,
                              InMobiInterstitialOnAdDisplayFailed onAdDisplayFailed,
                              InMobiInterstitialWillDisplay onAdWillDisplay,
                              InMobiInterstitialOnAdDisplayed onAdDisplayed,
                              InMobiInterstitialOnAdDismissed onAdDismissed,
                              InMobiInterstitialOnAdInteraction onAdInteraction,
                              InMobiInterstitialOnUserLeftApplication onUserLeftApplication,
                              InMobiInterstitialOnAdRewardActionCompleted onAdRewardActionCompleted){
    InMobiInterstitial *internalInterstitial = (__bridge InMobiInterstitial *)interstitial;
    internalInterstitial.onAdReceived = onAdReceived;
    internalInterstitial.onAdLoadSucceeded = onAdLoadSucceeded ;
    internalInterstitial.onAdLoadFailed = onAdLoadFailed;
    internalInterstitial.onAdDisplayFailed = onAdDisplayFailed;
    internalInterstitial.onAdWillDisplay = onAdWillDisplay;
    internalInterstitial.onAdDisplayed = onAdDisplayed;
    internalInterstitial.onAdDismissed = onAdDismissed;
    internalInterstitial.onAdInteraction = onAdInteraction;
    internalInterstitial.onUserLeftApplication = onUserLeftApplication;
    internalInterstitial.onAdRewardActionCompleted = onAdRewardActionCompleted;
}

#pragma End InMobiInterstitial APIs

void InMobiRelease(InMobiRef ref){
    if(ref){
        InMobiObjectCache *cache = [InMobiObjectCache sharedInstance];
        [cache.references removeObjectForKey:[(__bridge NSObject *)ref inmobi_referenceKey]];
    }
}



#pragma UnifiedId APIs

/// Creates a InMobiUnifiedIdService using unifiedIdClient. 
/// Returns a reference to the InMobiUnifiedIdService.
InMobiUnifiedIdServiceRef InMobiCreateUnifiedIdService(InMobiUnifiedIdClientRef *unifiedIdClient) {
    InMobiUnifiedIdService *unifiedIdService = [[InMobiUnifiedIdService alloc] initUnifiedService:unifiedIdClient];
    InMobiObjectCache *cache = [InMobiObjectCache sharedInstance];
    [cache.references setObject:unifiedIdService forKey:[unifiedIdService inmobi_referenceKey]];
    return (__bridge InMobiUnifiedIdServiceRef)unifiedIdService;
}

void Push(InMobiUnifiedIdServiceRef unifiedIdService, const char* inMobiUserDataModelJson) {
    
    IMUserDataModel *unifiedIdDatamodel = InMobiUnifiedIdModelFromJson(inMobiUserDataModelJson);
    InMobiUnifiedIdService *internalService = (__bridge InMobiUnifiedIdService *)unifiedIdService;
    [internalService push:unifiedIdDatamodel];
}

void FetchUnifiedIds(InMobiUnifiedIdServiceRef unifiedIdService) {
    InMobiUnifiedIdService *internalService = (__bridge InMobiUnifiedIdService *)unifiedIdService;
    [internalService fetchUnifiedIds];
}

void Reset(InMobiUnifiedIdServiceRef unifiedIdService) {
    InMobiUnifiedIdService *internalService = (__bridge InMobiUnifiedIdService *)unifiedIdService;
    [internalService reset];
}

///Sets the UnifiedId callbacks to be invoked after fetch completes
void SetUnifiedIdCallbacks(InMobiUnifiedIdServiceRef unifiedIdService,
                        InMobiOnFetchCompleted OnFetchCompleted){
    InMobiUnifiedIdService *internalService = (__bridge InMobiUnifiedIdService *)unifiedIdService;
    internalService.onFetchCompleted = OnFetchCompleted;
}

void EnableDebugMode(InMobiUnifiedIdServiceRef unifiedIdService, bool debugMode) {
    InMobiUnifiedIdService *internalService = (__bridge InMobiUnifiedIdService *)unifiedIdService;
    [internalService enableDebugMode: debugMode];
}

#pragma End UnifiedId APIs




