//
//   DDMASearch.m
//   DDMAMapKit_Private
//   Created by DDIsFriend on 2023/1/30.
    

#import "DDMASearch.h"
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <CoreLocation/CoreLocation.h>

@interface DDMASearch ()<AMapSearchDelegate>
@property (nonatomic, strong)AMapSearchAPI *search;

@property (nonatomic, assign)MASearchType searchType;

@end

@implementation DDMASearch
static NSString *const requestKey = @"request";
static NSString *const responseKey = @"response";
static NSString *const errorKey = @"error";

// MARK: <Class Initialize>
+ (void)startWithAppKey:(nullable NSString *)appKey{
    [[AMapServices sharedServices] setEnableHTTPS:YES];
    [AMapServices sharedServices].apiKey = appKey;
}

+ (void)agreePrivacy{
    [AMapSearchAPI updatePrivacyShow:AMapPrivacyShowStatusDidShow privacyInfo:AMapPrivacyInfoStatusDidContain];
    [AMapSearchAPI updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree];
}

// MARK: <Init>
- (instancetype)init{
    self = [super init];
    if (self == nil) return nil;

    return self;
}

// MARK: <Function>
- (void)setSearchOption:(AMapSearchObject *)searchOption{
    _searchOption = searchOption;
    MASearchType currentSearchType = kMASearchNone;
    if ([searchOption isMemberOfClass:[AMapPOIKeywordsSearchRequest class]]) {
        currentSearchType = kMASearchPOIKeywords;
    }else if ([searchOption isMemberOfClass:[AMapPOIAroundSearchRequest class]]){
        currentSearchType = kMASearchPOIAround;
    }else if ([searchOption isMemberOfClass:[AMapInputTipsSearchRequest class]]){
        currentSearchType = kMASearchInputTips;
    }else if ([searchOption isMemberOfClass:[AMapGeocodeSearchRequest class]]){
        currentSearchType = kMASearchGeocode;
    }else if ([searchOption isMemberOfClass:[AMapReGeocodeSearchRequest class]]){
        currentSearchType = kMASearchReGeocode;
    }else if ([searchOption isMemberOfClass:[AMapDrivingCalRouteSearchRequest class]]){
        currentSearchType = kMASearchDrivingCalRoute;
    }else if ([searchOption isMemberOfClass:[AMapRidingRouteSearchRequest class]]){
        currentSearchType = kMASearchRidingRoute;
    }
   
    self.searchType = currentSearchType;
}

- (void)refresh{
    if (self.searchOption == nil) {
        return;
    }
//    [self performSelector:@selector(refreshInSearchThread:) onThread:self.searchThread withObject:self.searchOption waitUntilDone:NO];
    [self refreshInSearchThread:self.searchOption];
}

- (void)refreshInSearchThread:(AMapSearchObject *)searchOption{
//    bool isUnlock = os_unfair_lock_trylock(&_requestLock);
//    if (!isUnlock) return;
    
    if (self.searchType & kMASearchPOIKeywords) {
        AMapPOIKeywordsSearchRequest *POIKeywordsSearchRequest = (AMapPOIKeywordsSearchRequest *)self.searchOption;
        POIKeywordsSearchRequest.page = 1;
        [self.search AMapPOIKeywordsSearch:POIKeywordsSearchRequest];
    }else if (self.searchType & kMASearchPOIAround){
        AMapPOIAroundSearchRequest *POIAroundSearchRequest = (AMapPOIAroundSearchRequest *)self.searchOption;
        POIAroundSearchRequest.page = 1;
        [self.search AMapPOIAroundSearch:POIAroundSearchRequest];
    }else if (self.searchType & kMASearchInputTips){
        [self.search AMapInputTipsSearch:(AMapInputTipsSearchRequest *)self.searchOption];
    }else if (self.searchType & kMASearchGeocode){
        [self.search AMapGeocodeSearch:(AMapGeocodeSearchRequest *)self.searchOption];
    }else if (self.searchType & kMASearchReGeocode){
        [self.search AMapReGoecodeSearch:(AMapReGeocodeSearchRequest *)self.searchOption];
    }else if (self.searchType & kMASearchDrivingCalRoute){
        [self.search AMapDrivingV2RouteSearch:(AMapDrivingCalRouteSearchRequest *)self.searchOption];
    }else if (self.searchType & kMASearchRidingRoute){
        [self.search AMapRidingRouteSearch:(AMapRidingRouteSearchRequest *)self.searchOption];
    }
}

- (void)loadMore{
    if (self.searchOption == nil) {
        return;
    }
//    [self performSelector:@selector(loadMoreInSearchThread:) onThread:self.searchThread withObject:self.searchOption waitUntilDone:NO];
    [self loadMoreInSearchThread:self.searchOption];
}

- (void)loadMoreInSearchThread:(AMapSearchObject *)searchOption{
//    bool isUnlock = os_unfair_lock_trylock(&_requestLock);
//    if (!isUnlock) return;
    
    if (self.searchType & kMASearchPOIKeywords) {
        AMapPOIKeywordsSearchRequest *POIKeywordsSearchRequest = (AMapPOIKeywordsSearchRequest *)self.searchOption;
        POIKeywordsSearchRequest.page++;
        [self.search AMapPOIKeywordsSearch:POIKeywordsSearchRequest];
    }else if (self.searchType & kMASearchPOIAround){
        AMapPOIAroundSearchRequest *POIAroundSearchRequest = (AMapPOIAroundSearchRequest *)self.searchOption;
        POIAroundSearchRequest.page++;
        [self.search AMapPOIAroundSearch:POIAroundSearchRequest];
    }else{
        return;
    }
}

- (void)onRequestFailedInSearchThread:(NSDictionary *)dict{
    if (self.onRequestFailed) {
        self.onRequestFailed(dict[requestKey], dict[errorKey]);
    }
//    os_unfair_lock_unlock(&_requestLock);
}

- (void)onResponseInSearchThread:(NSDictionary *)dict{
    if (self.onResponseDone) {
        self.onResponseDone(dict[requestKey], dict[responseKey]);
    }
//    os_unfair_lock_unlock(&_requestLock);
}

// MARK: <AMapSearchDelegate>
- (void)AMapSearchRequest:(id)request didFailWithError:(NSError *)error{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[requestKey] = request;
    dict[errorKey] = error;
    
//    [self performSelector:@selector(onRequestFailedInSearchThread:) onThread:self.searchThread withObject:dict waitUntilDone:NO];
    [self onRequestFailedInSearchThread:dict];
}

- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[requestKey] = request;
    dict[responseKey] = response;
    
//    [self performSelector:@selector(onResponseInSearchThread:) onThread:self.searchThread withObject:dict waitUntilDone:NO];
    [self onResponseInSearchThread:dict];
}

- (void)onGeocodeSearchDone:(AMapGeocodeSearchRequest *)request response:(AMapGeocodeSearchResponse *)response{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[requestKey] = request;
    dict[responseKey] = response;
    
//    [self performSelector:@selector(onResponseInSearchThread:) onThread:self.searchThread withObject:dict waitUntilDone:NO];
    [self onResponseInSearchThread:dict];
}

- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[requestKey] = request;
    dict[responseKey] = response;
    
//    [self performSelector:@selector(onResponseInSearchThread:) onThread:self.searchThread withObject:dict waitUntilDone:NO];
    [self onResponseInSearchThread:dict];
}

- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[requestKey] = request;
    dict[responseKey] = response;
    
//    [self performSelector:@selector(onResponseInSearchThread:) onThread:self.searchThread withObject:dict waitUntilDone:NO];
    [self onResponseInSearchThread:dict];
}

- (void)onRouteSearchDone:(AMapRouteSearchBaseRequest *)request response:(AMapRouteSearchResponse *)response{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[requestKey] = request;
    dict[responseKey] = response;
    
//    [self performSelector:@selector(onResponseInSearchThread:) onThread:self.searchThread withObject:dict waitUntilDone:NO];
    [self onResponseInSearchThread:dict];
}

// MARK: <Lazy>
- (AMapSearchAPI *)search{
    if (_search == nil) {
        _search = [[AMapSearchAPI alloc] init];
        _search.delegate = self;
    }
    return _search;
}
@end

@implementation DDMASearch (Route)

DDMACoordinateKey const DDMACoords = @"coords";
DDMACoordinateKey const DDMACoordsCount = @"coordsCount";
DDMACoordinateKey const DDMALocations = @"locations";

+ (AMapSearchObject *)drivingCalRouteSearchRequestWithOrigin:(CLLocationCoordinate2D)origin destination:(CLLocationCoordinate2D)destination strategy:(NSInteger)strategy type:(MADriveSearchType)type {
    AMapDrivingCalRouteSearchRequest *request = [[AMapDrivingCalRouteSearchRequest alloc] init];
    if (type == kMADriveSearchPolyline) {
        request.showFieldType = AMapDrivingRouteShowFieldTypePolyline;
    }else if (type == kMADriveSearchCost){
        request.showFieldType = AMapDrivingRouteShowFieldTypeCost;
    }
    request.strategy = strategy;
    request.origin = [AMapGeoPoint locationWithLatitude:origin.latitude
                                           longitude:origin.longitude];
    request.destination = [AMapGeoPoint locationWithLatitude:destination.latitude
                                                longitude:destination.longitude];
    return request;
}

+ (AMapSearchObject *)ridingRouteSearchRequestWithOrigin:(CLLocationCoordinate2D)origin destination:(CLLocationCoordinate2D)destination{
    AMapRidingRouteSearchRequest *request = [[AMapRidingRouteSearchRequest alloc] init];
    request.showFieldsType = AMapRidingRouteShowFieldsTypeAll;
    request.origin = [AMapGeoPoint locationWithLatitude:origin.latitude
                                           longitude:origin.longitude];
    request.destination = [AMapGeoPoint locationWithLatitude:destination.latitude
                                                longitude:destination.longitude];
    return request;
}

+ (NSMutableArray<DDMACoordinate> *)coordsArrayWithRouteSearchResponse:(AMapRouteSearchResponse *)routeSearchResponse{
    NSMutableArray<NSDictionary *> *coordinateArr = [NSMutableArray array];
    [routeSearchResponse.route.paths enumerateObjectsUsingBlock:^(AMapPath * _Nonnull aMapPath, NSUInteger idx, BOOL * _Nonnull stop) {
        NSMutableArray *coorArray = [NSMutableArray array];
        [aMapPath.steps enumerateObjectsUsingBlock:^(AMapStep * _Nonnull step, NSUInteger idx, BOOL * _Nonnull stop) {
            [coorArray addObjectsFromArray:[step.polyline componentsSeparatedByString:@";"]];
        }];
        CLLocationCoordinate2D *coords = new CLLocationCoordinate2D[coorArray.count];
        [coorArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            NSArray *coordinate = [obj componentsSeparatedByString:@","];
            coords[idx].latitude = [coordinate.lastObject floatValue];
            coords[idx].longitude = [coordinate.firstObject floatValue];
        }];
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[DDMACoordsCount] = @(coorArray.count);
        dict[DDMACoords] = [NSValue valueWithPointer:coords];
        [coordinateArr addObject:dict];
    }];
    return coordinateArr;
}

+ (NSMutableArray<NSMutableArray<CLLocation *> *> *)locationsArrayWithRouteSearchResponse:(AMapRouteSearchResponse *)routeSearchResponse{
    NSMutableArray<NSMutableArray<CLLocation *> *> *coordinateArr = [NSMutableArray array];
    [routeSearchResponse.route.paths enumerateObjectsUsingBlock:^(AMapPath * _Nonnull aMapPath, NSUInteger idx, BOOL * _Nonnull stop) {
        NSMutableArray *coorArray = [NSMutableArray array];
        [aMapPath.steps enumerateObjectsUsingBlock:^(AMapStep * _Nonnull step, NSUInteger idx, BOOL * _Nonnull stop) {
            [coorArray addObjectsFromArray:[step.polyline componentsSeparatedByString:@";"]];
        }];
        NSMutableArray<CLLocation *> *locations = [NSMutableArray array];
        [coorArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            NSArray *coordinate = [obj componentsSeparatedByString:@","];
            [locations addObject:[[CLLocation alloc] initWithLatitude:[coordinate.lastObject floatValue] longitude:[coordinate.firstObject floatValue]]];
        }];
        [coordinateArr addObject:locations];
    }];
    return coordinateArr;
}
@end
