
#import "SLLocationManager.h"
#import "JZLocationConverter.h"

#define authStatus(status) @"#status"

@interface SLLocationManager () <CLLocationManagerDelegate>

@property (nonatomic, strong) NSMutableArray *completeBlocks;
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, copy) YMCurrentLocationBlock locationBlock;
//持续定位
@property (nonatomic, strong) CLLocationManager *holdLocationManager;
@property (nonatomic, assign) BOOL holdLocating;// 持续定位：正在定位

@end

@implementation SLLocationManager

+ (instancetype)shareInstance
{
    static SLLocationManager *_instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[[self class] alloc] init];
    });
    return _instance;
}

- (void)dealloc
{
    NSLog(@"释放 %s", __func__);
}

- (NSMutableArray *)completeBlocks
{
    if (!_completeBlocks) {
        _completeBlocks = [NSMutableArray array];
    }
    return _completeBlocks;
}

- (void)setCurrentLocation:(CLLocation *)currentLocation
{
    _currentLocation = currentLocation;
}

- (void)getLocationComplete:(YMCurrentLocationBlock)completeBlock
                
{
//    if (self.currentLocation) {
//        [self ym_reverseGeocodeLocation:self.currentLocation completionHandler:completeBlock];
//        return;
//    }
    [self.completeBlocks addObject:completeBlock];
    CLAuthorizationStatus authStatus = [CLLocationManager  authorizationStatus];
    if(authStatus == kCLAuthorizationStatusNotDetermined) {
        [self.locationManager requestWhenInUseAuthorization];
    } else {
        [self.locationManager startUpdatingLocation];
    }
}

+ (BOOL)locationEnabled
{
    if (![CLLocationManager locationServicesEnabled]) {
        return NO;
    }
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
    if (kCLAuthorizationStatusAuthorizedWhenInUse == status ||
        kCLAuthorizationStatusAuthorizedAlways == status) {
        return YES;
    }
    return NO;
}

- (CLLocation *)getCurrentLocation:(YMCurrentLocationBlock)locationBlock
{
    if (NSThread.currentThread.isMainThread) {
        [self getCurrentLocationInMainThread:locationBlock];
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self getCurrentLocationInMainThread:locationBlock];
        });
    }
    return self.currentLocation;
}

- (void)getCurrentLocationInMainThread:(YMCurrentLocationBlock)locationBlock
{
    if (!self.currentLocation &&
        [SLLocationManager locationEnabled]) {
        if (self.holdLocating) {
            return;
        }
        self.holdLocating = YES;
        self.locationBlock = locationBlock;
        [self.holdLocationManager startUpdatingLocation];
    } else {
        if (locationBlock) {
            locationBlock(self.currentLocation);
        }
    }
}

/// 清空当前定位
+ (void)clearLocation
{
    [[SLLocationManager shareInstance] setCurrentLocation:nil];
}
/// 清空当前地址
+ (void)clearAddress
{
    [[SLLocationManager shareInstance] setState:@""];
    [[SLLocationManager shareInstance] setProvince:@""];
    [[SLLocationManager shareInstance] setCity:@""];
}
/// 清空全部
+ (void)clearAll
{
    [self clearLocation];
    [self clearAddress];
}

#pragma mark - CLLocationManagerDelegate
// 授权状态变更
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    if (manager == _locationManager) {
        if (CLLocationManager.authorizationStatus != kCLAuthorizationStatusNotDetermined) {
            [self.locationManager startUpdatingLocation];
        }
    }
}
// 更新地位回调
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    if (manager == _locationManager) {
        if (locations.count == 0) {
            for (YMCurrentLocationBlock completeBlock in self.completeBlocks) {
                completeBlock(nil);
            }
            [self.completeBlocks removeAllObjects];
            return;
        }
        [self.locationManager stopUpdatingLocation];
        
        CLLocation *newLocation = [locations lastObject];
        if (newLocation) {
            [self ym_reverseGeocodeLocation:newLocation completionHandler:^(void) {
                for (YMCurrentLocationBlock completeBlock in self.completeBlocks) {
                    completeBlock(newLocation);
                }
                [self.completeBlocks removeAllObjects];
            }];
        }
    } else if (manager == _holdLocationManager) {
        self.holdLocating = NO;
        if (locations.count > 0) {
            [self.holdLocationManager stopUpdatingLocation];
            CLLocation *newLocation = [locations lastObject];
            if (self.locationBlock) {
                self.locationBlock(newLocation);
            }
        }
    }
    
}
// 定位失败回调
- (void)locationManager:(CLLocationManager *)manager
       didFailWithError:(NSError *)error
{
    if (manager == _locationManager) {
        [self.locationManager stopUpdatingLocation];
        if (CLLocationManager.authorizationStatus != kCLAuthorizationStatusNotDetermined) {
            for (YMCurrentLocationBlock completeBlock in self.completeBlocks) {
                completeBlock(manager.location);
            }
            [self.completeBlocks removeAllObjects];
        }
    } else if (manager == _holdLocationManager) {
        [self.holdLocationManager stopUpdatingLocation];
        self.holdLocating = NO;
        if (self.locationBlock) {
            self.locationBlock(nil);
        }
    }
}

// 反向地址编码
- (void)ym_reverseGeocodeLocation:(CLLocation *)location
                completionHandler:(void(^)(void))completionHandler
{
    if (self.state.length && self.city.length) {
        if (completionHandler) {
            completionHandler();
        }
        return;
    }
    if (@available(iOS 10.0, *)) {
        NSString *countryCode = [NSLocale autoupdatingCurrentLocale].countryCode;
        if ([countryCode isEqualToString:@"CN"] ||
            [countryCode isEqualToString:@"HK"] ||
            [countryCode isEqualToString:@"MO"] ||
            [countryCode isEqualToString:@"TW"]) {
            CLLocationCoordinate2D cor = [JZLocationConverter wgs84ToGcj02:location.coordinate];
            location = [[CLLocation alloc] initWithLatitude:cor.latitude longitude:cor.longitude];
            //YMLLog(@"转换后lat：%f", location.coordinate.latitude);
            //YMLLog(@"转换后long：%f", location.coordinate.longitude);
        }
    } else {
        NSString *localeIdentifier = [NSLocale autoupdatingCurrentLocale].localeIdentifier;
        if ([localeIdentifier.lowercaseString hasSuffix:@"cn"] ||
            [localeIdentifier.lowercaseString hasSuffix:@"hk"] ||
            [localeIdentifier.lowercaseString hasSuffix:@"mo"] ||
            [localeIdentifier.lowercaseString hasSuffix:@"tw"]) {
            CLLocationCoordinate2D cor = [JZLocationConverter wgs84ToGcj02:location.coordinate];
            location = [[CLLocation alloc] initWithLatitude:cor.latitude longitude:cor.longitude];
            //YMLLog(@"转换后lat：%f", location.coordinate.latitude);
            //YMLLog(@"转换后long：%f", location.coordinate.longitude);
        }
    }
    
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        //YMLLog(@"placemarks:%@(%@)", placemarks, error);
        if (placemarks.count > 0) {
            CLPlacemark *first = placemarks[0];
            
            NSString *country = first.country;
            NSString *province = first.administrativeArea;
            NSString *city = first.locality;
            
            self.state = country ? : @"";
            self.province = province ? : @"";
            self.city = city ? : @"";
        }
        if (completionHandler) {
            completionHandler();
        }
    }];
}


#pragma mark - instance
- (CLLocationManager *)locationManager
{
    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
        _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        _locationManager.distanceFilter = 5.0;
    }
    return _locationManager;
}

- (CLLocationManager *)holdLocationManager
{
    if (!_holdLocationManager) {
        _holdLocationManager = [[CLLocationManager alloc] init];
        _holdLocationManager.delegate = self;
        _holdLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
        _holdLocationManager.distanceFilter = 5.0;
    }
    return _holdLocationManager;
}

@end
