//
//  GMediator.m
//  GMediator
//
//  Created by Thierry on 16/3/13.
//  Copyright © 2016年 Thierry. All rights reserved.
//

#import "GMediator.h"
#import "NSString+GMediator.h"

static GMediator *sharedManager = nil;

@implementation GMediator

+ (instancetype)sharedInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedManager = [[GMediator alloc] init];
        NSAssert([sharedManager handleNotRespond] != nil, @"主项目需要实现一个Target_NotFound类，并实现一个notFound方法，返回一个默认值");
    });
    return sharedManager;
}

- (BOOL)performActionWithUrl:(NSString *)url completion:(void (^ __nullable)(NSDictionary * _Nonnull))completion
{
    @try {
        if (![url hasPrefix:_scheme]) {
            return NO;
        } else{
            // 因为url有可能是包含中文（未转义的字符），所以需要先转义。正因如果，url可以被客户端再一次转义，所以在处理url query时会有二次转义检查
            NSString *encodeUrlScheme = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            NSURL *url = [NSURL URLWithString:encodeUrlScheme];
            if (!url) {
                return NO;
            }

            // 从路由表中获取的协议host所对应的Target_Action
            NSDictionary *targetAction = [_routingDic objectForKey:url.host];
            if (!targetAction) {
                return NO;
            }
            NSString *targetName = [targetAction objectForKey:@"target"];
            NSString *actionName = [targetAction objectForKey:@"action"];
            if (targetName.length == 0 || actionName.length == 0) {
                return NO;
            }

            // 从协议url中取得 query 参数
            NSDictionary *params = [encodeUrlScheme GMediator_urlQueryToDictionary];
            id result = [self performOnTarget:targetName action:actionName params:params];
            if (completion) {
                if (result) {
                    completion(@{@"result": result});
                } else {
                    completion(nil);
                }
            }

            return YES;
        }
    }
    @catch (NSException *exception) {
        return NO;
    }
}

- (UIViewController *)controllerFromTarget:(NSString *)targetName action:(NSString *)actionName params:(nullable NSDictionary *)params {
    UIViewController *c = [self performOnTarget:targetName action:actionName params:params];
    return c;
}

- (nullable id)performOnTarget:(NSString *)targetName action:(NSString *)actionName params:(nullable NSDictionary *)params {
    Class targetClass = [self findOCTargetClass:targetName];
    if (targetClass != nil) {
        return [self target:targetClass action:actionName params:params];
    }
    targetClass = [self findSwiftTargetClass:targetName];
    if (targetClass != nil) {
        return [self target:targetClass action:actionName params:params];
    }
    NSAssert(0, @"GMediator: 没有找到 target %@ 类", targetName);
    return [self handleNotRespond];
}

- (nullable id)target:(Class)targetClass action:(NSString *)actionName params:(nullable NSDictionary *)params {
    // 构造SEL
    NSString *actionString = [NSString stringWithFormat:@"Action_%@%@", actionName, (params == nil ? @"" : @":")];
    SEL action = NSSelectorFromString(actionString);

    // 尝试实例方法调用
    id target = [[targetClass alloc] init];
    if ([target respondsToSelector:action]) {
        // 判断返回值类型是否为void，对于void的类型的调用，需要做特别处理
        const char *returnType = [target methodSignatureForSelector:action].methodReturnType;
        if (*returnType == 'v') {
            [target performSelector:action withObject:params];
            return nil;
        } else {
            return [target performSelector:action withObject:params];;
        }
    } else {
        NSAssert(0, @"GMediator: %@ 不能响应 %@ 方法，确保调用的是实例方法", NSStringFromClass(targetClass), actionString);
        return [self handleNotRespond];
    }
}

- (nullable Class)findOCTargetClass:(NSString *)targetName {
    NSString *targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
    Class targetClass = NSClassFromString(targetClassString);
    return targetClass;
}

- (nullable Class)findSwiftTargetClass:(NSString *)targetName {
    /*
     尝试获取自定义的 CFProductModuleName，如果找不到会尝试获取 CFBundleName，一般情况下 CFBundleName 会在 info.plist 里指向 build setting 中的 product name.
     而 product name 常常与 module name 是一样的.
     当然有例外, 详情查看
     https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-ID138 中的 Naming Your Product Module
     */
    NSString *swiftClassPrefix = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFProductModuleName"];
    if (swiftClassPrefix == nil) {
        swiftClassPrefix = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleName"];
    }
    NSString *targetClassString = [NSString stringWithFormat:@"%@.Target_%@", swiftClassPrefix, targetName];
    Class targetClass = NSClassFromString(targetClassString);
    return targetClass;
}

- (nullable id)handleNotRespond {
    // 这里是处理无响应请求的地方，如果无响应，则尝试调用 NotFoundTarget 的notFound方法统一处理
    id target = [NSClassFromString(@"Target_NotFound") new];
    SEL action = NSSelectorFromString(@"notFound");
    if ([target respondsToSelector:action]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        return [target performSelector:action];
#pragma clang diagnostic pop
    } else {
        return nil;
    }
}

@end