//
//  RCTAMapModule.m
//  RCTAMapModule
//
//  Created by Train on 2017/9/22.
//  Copyright © 2017年 Train. All rights reserved.
//

#import "RCTAMapModule.h"

#define DefaultLocationTimeout 10
#define DefaultReGeocodeTimeout 5

@interface RCTAMapModule() <AMapLocationManagerDelegate>

@property (nonatomic, strong) AMapLocationManager *locationManager;

@property (nonatomic, copy) AMapLocatingCompletionBlock completionBlock;

@end

@implementation RCTAMapModule

@synthesize bridge = _bridge;

RCT_EXPORT_MODULE(AMapLocation);

RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback){
    callback(@[@"string test"]);
}

RCT_EXPORT_METHOD(init:(NSDictionary *)options)
{
    
    if(self.locationManager != nil) {
        return;
    }
    
    self.locationManager = [[AMapLocationManager alloc] init];
    
    [self.locationManager setDelegate:self];
    
    [self setOptions:options];
    
    [self initCompleteBlock];
}

RCT_EXPORT_METHOD(setOptions:(NSDictionary *)options)
{
    CLLocationAccuracy locationMode = kCLLocationAccuracyHundredMeters;
    BOOL pausesLocationUpdatesAutomatically = NO;
    BOOL allowsBackgroundLocationUpdates = YES;
    int locationTimeout = DefaultLocationTimeout;
    int reGeocodeTimeout = DefaultReGeocodeTimeout;
    
    if(options != nil) {
        
        NSArray *keys = [options allKeys];
        
        if([keys containsObject:@"locationMode"]) {
            locationMode = [[options objectForKey:@"locationMode"] doubleValue];
        }
        
        if([keys containsObject:@"pausesLocationUpdatesAutomatically"]) {
            pausesLocationUpdatesAutomatically = [[options objectForKey:@"pausesLocationUpdatesAutomatically"] boolValue];
        }
        
        if([keys containsObject:@"allowsBackgroundLocationUpdates"]) {
            allowsBackgroundLocationUpdates = [[options objectForKey:@"allowsBackgroundLocationUpdates"] boolValue];
        }
        
        
        if([keys containsObject:@"locationTimeout"]) {
            locationTimeout = [[options objectForKey:@"locationTimeout"] intValue];
        }
        
        if([keys containsObject:@"reGeocodeTimeout"]) {
            reGeocodeTimeout = [[options objectForKey:@"reGeocodeTimeout"] intValue];
        }
    }
    
    //设置期望定位精度
    [self.locationManager setDesiredAccuracy:locationMode];
    
    //设置是否允许系统暂停定位
    [self.locationManager setPausesLocationUpdatesAutomatically:pausesLocationUpdatesAutomatically];
    
    //设置是否允许在后台定位
    [self.locationManager setAllowsBackgroundLocationUpdates:allowsBackgroundLocationUpdates];
    
    //设置定位超时时间
    [self.locationManager setLocationTimeout:locationTimeout];
    
    //设置逆地理超时时间
    [self.locationManager setReGeocodeTimeout:reGeocodeTimeout];
    
}

RCT_EXPORT_METHOD(cleanUp)
{
    //停止定位
    [self.locationManager stopUpdatingLocation];
    
    [self.locationManager setDelegate:nil];
    
    self.locationManager = nil;
}



RCT_EXPORT_METHOD(getReGeocode)
{
    //进行单次带逆地理定位请求
    [self.locationManager requestLocationWithReGeocode:YES completionBlock:self.completionBlock];
}

RCT_EXPORT_METHOD(getLocation)
{
    //进行单次定位请求
    [self.locationManager requestLocationWithReGeocode:NO completionBlock:self.completionBlock];
}

RCT_EXPORT_METHOD(startUpdatingLocation)
{
    //开始进行连续定位
    [self.locationManager startUpdatingLocation];
}

RCT_EXPORT_METHOD(stopUpdatingLocation)
{
    //停止连续定位
    [self.locationManager stopUpdatingLocation];
    
}

#pragma mark - Initialization

- (void)initCompleteBlock
{
    
    self.completionBlock = ^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error)
    {
        NSDictionary *resultDic;
        
        if(error != nil){
            
            resultDic = [self setErrorResult:error];
            
            [self.bridge.eventDispatcher sendAppEventWithName:@"amap.location.onLocationResult"
                                                         body:resultDic];
            return;

        }
        if (error != nil && error.code == AMapLocationErrorLocateFailed)
        {
            //定位错误：此时location和regeocode没有返回值，不进行annotation的添加
            NSLog(@"定位错误:{%ld - %@};", (long)error.code, error.localizedDescription);
            
            return;
        }
        else if (error != nil
                 && (error.code == AMapLocationErrorReGeocodeFailed
                     || error.code == AMapLocationErrorTimeOut
                     || error.code == AMapLocationErrorCannotFindHost
                     || error.code == AMapLocationErrorBadURL
                     || error.code == AMapLocationErrorNotConnectedToInternet
                     || error.code == AMapLocationErrorCannotConnectToHost))
        {
            //逆地理错误：在带逆地理的单次定位中，逆地理过程可能发生错误，此时location有返回值，regeocode无返回值，进行annotation的添加
            NSLog(@"逆地理错误:{%ld - %@};", (long)error.code, error.localizedDescription);
            return;
        }
        else if (error != nil && error.code == AMapLocationErrorRiskOfFakeLocation)
        {
            //存在虚拟定位的风险：此时location和regeocode没有返回值，不进行annotation的添加
            NSLog(@"存在虚拟定位的风险:{%ld - %@};", (long)error.code, error.localizedDescription);
            return;
        }
        else
        {
            
            //没有错误：location有返回值，regeocode是否有返回值取决于是否进行逆地理操作，进行annotation的添加
            resultDic = [self setSuccessResult:location regeocode:regeocode];
            
            [self.bridge.eventDispatcher sendAppEventWithName:@"amap.location.onLocationResult"
                                                         body:resultDic];

        }
        
    };
}

- (void)dealloc
{
    [self cleanUp];
}

- (NSDictionary*)setErrorResult:(NSError *)error
{
    NSDictionary *resultDic;
    
    resultDic = @{
                  @"error": @{
                          @"code": @(error.code),
                          @"localizedDescription": error.localizedDescription
                          }
                  };
    return resultDic;
}

- (NSDictionary*)setSuccessResult:(CLLocation *)location regeocode:(AMapLocationReGeocode *)regeocode
{
    NSDictionary *resultDic;
    
    //得到定位信息
    if (location)
    {
        if(regeocode && regeocode.province) {
            resultDic = @{
                          @"horizontalAccuracy": @(location.horizontalAccuracy),
                          @"verticalAccuracy": @(location.verticalAccuracy),
                          @"coordinate": @{
                                  @"latitude": @(location.coordinate.latitude),
                                  @"longitude": @(location.coordinate.longitude),
                                  },
                          @"formattedAddress": regeocode.formattedAddress,
                          @"country": regeocode.country,
                          @"province": regeocode.province,
                          @"city": regeocode.city,
                          @"district": regeocode.district,
                          @"citycode": regeocode.citycode,
                          @"adcode": regeocode.adcode,
                          @"street": regeocode.street,
                          @"number": regeocode.number,
                          @"POIName": regeocode.POIName,
                          //@"AOIName": regeocode.AOIName
                          };
        }
        else {
            resultDic = @{
                          @"horizontalAccuracy": @(location.horizontalAccuracy),
                          @"verticalAccuracy": @(location.verticalAccuracy),
                          @"coordinate": @{
                                  @"latitude": @(location.coordinate.latitude),
                                  @"longitude": @(location.coordinate.longitude),
                                  }
                          };
            
        }
    }
    else {
        resultDic = @{
                      @"error": @{
                              @"code": @(-1),
                              @"localizedDescription": @"定位结果不存在"
                              }
                      };
    }
    return resultDic;
}


- (NSDictionary *)constantsToExport
{
    return @{
             @"locationMode": @{
                     @"bestForNavigation": @(kCLLocationAccuracyBestForNavigation),
                     @"best": @(kCLLocationAccuracyBest),
                     @"nearestTenMeters": @(kCLLocationAccuracyNearestTenMeters),
                     @"hundredMeters": @(kCLLocationAccuracyHundredMeters),
                     @"kilometer":  @(kCLLocationAccuracyKilometer),
                     @"threeKilometers": @(kCLLocationAccuracyThreeKilometers)
                     }
             };
}

@end

