//
// LocationManager.m
// Project
//
// Created by 杨殷杭 on 16/12/22.
//
//

#import "LocationManager.h"
#import "CocoaUtils.h"
#import <BlocksKit/BlocksKit.h>

@interface LocationManager () <CLLocationManagerDelegate>
@property (nonatomic, assign) CLAuthorizationStatus authorizationStatus;
@property (nonatomic, copy) void (^completion) (BOOL granted, CLLocation *location, NSError *error);
@property (nonatomic, copy) void (^authorization) (BOOL granted);
@end

@implementation LocationManager

#pragma mark - Public

+ (void)locationManager:(CLLocationManager *)manager requestAccessForAuthorizationStatus:(CLAuthorizationStatus)status completionHandler:(void (^) (BOOL granted))completionHandler {
	if (status != kCLAuthorizationStatusAuthorizedWhenInUse && status != kCLAuthorizationStatusAuthorizedAlways) {
		return;
	}
	LocationManager *_manager = [LocationManager sharedManagers][@"Authorization"];
	_manager.authorizationStatus = status;
	_manager.authorization = completionHandler;
	[_manager requestWithLocationManager:manager];
}

+ (void)locationManager:(CLLocationManager *)manager requestLocationWithCompletion:(void (^) (BOOL granted, CLLocation *location, NSError *error))completion {
	LocationManager *_manager = [LocationManager sharedManagers][@"LocationRequest"];
	_manager.completion = completion;
	[_manager requestWithLocationManager:manager];
}

#pragma mark - Private

+ (NSDictionary<NSString *, LocationManager *> *)sharedManagers {
	static dispatch_once_t onceToken;
	static NSDictionary *dict;
	dispatch_once(&onceToken, ^{
		dict = @{ @"Authorization" : [LocationManager new], @"LocationRequest" : [LocationManager new] };
	});
	return dict;
}

- (void)requestWithLocationManager:(CLLocationManager *)manager {
	if (![CLLocationManager locationServicesEnabled]) {
		[self notGrantedWithLocationManager:manager];
		return;
	}
	manager.delegate = self;
	CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
	if (status == kCLAuthorizationStatusNotDetermined) {
		if (self == [LocationManager sharedManagers][@"Authorization"]) {
			if (self.authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse) {
				[manager requestWhenInUseAuthorization];
			} else if (self.authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
				[manager requestAlwaysAuthorization];
			}
		} else if (self == [LocationManager sharedManagers][@"LocationRequest"]) {
			[manager requestWhenInUseAuthorization];
		}
	} else {
		[self locationManager:manager changedAuthorizationStatus:status];
	}
}

- (void)notGrantedWithLocationManager:(CLLocationManager *)manager {
	if (self == [LocationManager sharedManagers][@"Authorization"]) {
		if (self.authorization) {
			self.authorization(NO);
		}
		[self dismissWithLocationManager:manager];
	} else if (self == [LocationManager sharedManagers][@"LocationRequest"]) {
		if (self.completion) {
			self.completion(NO, nil, nil);
		}
		[self dismissWithLocationManager:manager];
	}
}

- (void)dismissWithLocationManager:(CLLocationManager *)manager {
	if (self == [LocationManager sharedManagers][@"Authorization"]) {
		self.authorization = nil;
		manager.delegate = nil;
	} else if (self == [LocationManager sharedManagers][@"LocationRequest"]) {
		self.completion = nil;
		manager.delegate = nil;
	}
}

- (void)locationManager:(CLLocationManager *)manager changedAuthorizationStatus:(CLAuthorizationStatus)status {
	if (self == [LocationManager sharedManagers][@"Authorization"] && self.authorizationStatus == kCLAuthorizationStatusAuthorizedAlways && status == kCLAuthorizationStatusAuthorizedWhenInUse) {
		[self notGrantedWithLocationManager:manager];
	} else if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
		if (self == [LocationManager sharedManagers][@"Authorization"]) {
			if (self.authorization) {
				self.authorization(YES);
			}
			[self dismissWithLocationManager:manager];
		} else if (self == [LocationManager sharedManagers][@"LocationRequest"]) {
			if ([manager respondsToSelector:@selector(requestLocation)]) {
				[manager requestLocation];
			} else {
				[manager startUpdatingLocation];
			}
		}
	} else if (status == kCLAuthorizationStatusDenied || status == kCLAuthorizationStatusRestricted) {
		[self notGrantedWithLocationManager:manager];
	}
}

#pragma mark - Location manager delegate

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
	[self locationManager:manager changedAuthorizationStatus:status];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
	if (self == [LocationManager sharedManagers][@"Authorization"]) {
	} else if (self == [LocationManager sharedManagers][@"LocationRequest"]) {
		if (![manager respondsToSelector:@selector(requestLocation)]) {
			[manager stopUpdatingLocation];
		}
		if (self.completion) {
			self.completion(YES, locations.lastObject, nil);
		}
		[self dismissWithLocationManager:manager];
	}
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
	if (self == [LocationManager sharedManagers][@"Authorization"]) {
	} else if (self == [LocationManager sharedManagers][@"LocationRequest"]) {
		if (![manager respondsToSelector:@selector(requestLocation)]) {
			[manager stopUpdatingLocation];
		}
		if (self.completion) {
			self.completion(YES, nil, error);
		}
		[self dismissWithLocationManager:manager];
	}
}

@end
