//
//  MyEventBus.m
//  nochange
//
//  Created by mac on 2024/7/30.
//

#import "MyEventBus.h"
#import <objc/runtime.h>


@interface MyEventBus()
{

}

@property (nonatomic, strong) NSMutableDictionary<NSString *, NSMutableArray *> *subscribers;

@end

@implementation MyEventBus

+ (instancetype)sharedInstance {
    static MyEventBus *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _subscribers = [NSMutableDictionary dictionary];
    }
    return self;
}

- (void)registerSubscriber:(id)subscriber {
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList([subscriber class], &methodCount);
    
    for (unsigned int i = 0; i < methodCount; i++) {
        SEL selector = method_getName(methods[i]);
        NSString *selectorName = NSStringFromSelector(selector);
        
        if ([selectorName hasPrefix:@"onEvent"]) {
            NSString *eventName = [selectorName substringFromIndex:7];
            if (![self.subscribers objectForKey:eventName]) {
                [self.subscribers setObject:[NSMutableArray array] forKey:eventName];
            }
            [[self.subscribers objectForKey:eventName] addObject:subscriber];
        }
    }
    
    free(methods);
}

- (void)unregisterSubscriber:(id)subscriber {
    [self.subscribers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSMutableArray *obj, BOOL *stop) {
        [obj removeObject:subscriber];
    }];
}

- (void)postEvent:(NSString *)eventName withObject:(id)object {
    NSMutableArray *eventSubscribers = [self.subscribers objectForKey:[NSString stringWithFormat:@"%@:", eventName]];
    for (id subscriber in eventSubscribers) {
        SEL selector = NSSelectorFromString([NSString stringWithFormat:@"onEvent%@:", eventName]);
        if ([subscriber respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [subscriber performSelector:selector withObject:object];
#pragma clang diagnostic pop
        }
    }
}

@end
