//
//  ZBBaseDestination.m
//  Pods-ZBLog_Example
//
//  Created by Jumbo on 2021/3/10.
//

#import "ZBBaseDestination.h"
#import "ZBLog.h"
#import "XXGPlayKitConfig.h"

@implementation ZBLevelString @end
@implementation ZBLevelColor @end

@interface ZBBaseDestination()

@property (nonatomic, strong) NSDateFormatter *zb_formatter;

@end

@implementation ZBBaseDestination

- (instancetype)init {
    self = [super init];

    if (self) {

        NSString *uuid = NSUUID.UUID.UUIDString;
        NSString *queueLabel = [NSString stringWithFormat:__data_core.xxpk_tools_logger_queue_label,uuid];
        _zb_queue = dispatch_queue_create(queueLabel.UTF8String, NULL);

        _zb_asynchronously = YES;

        _zb_minLevel = ZBLogLevelVerbose;

        _zb_levelString = [ZBLevelString new];
        _zb_levelString.zb_verbose = __data_core.xxpk_tools_logger_level_verbose;
        _zb_levelString.zb_debug   = __data_core.xxpk_tools_logger_level_debug;
        _zb_levelString.zb_info    = __data_core.xxpk_tools_logger_level_info;
        _zb_levelString.zb_warning = __data_core.xxpk_tools_logger_level_warning;
        _zb_levelString.zb_error   = __data_core.xxpk_tools_logger_level_error;
        _zb_levelString.zb_all     = __data_core.xxpk_tools_logger_level_all;

        _zb_levelColor = [ZBLevelColor new];
        _zb_levelColor.zb_verbose = __data_core.xxpk_tools_logger_color_verbose;   // silver
        _zb_levelColor.zb_debug   = __data_core.xxpk_tools_logger_color_debug;   // green
        _zb_levelColor.zb_info    = __data_core.xxpk_tools_logger_color_info;   // blue
        _zb_levelColor.zb_warning = __data_core.xxpk_tools_logger_color_warning;   // yellow
        _zb_levelColor.zb_error   = __data_core.xxpk_tools_logger_color_error;   // red
        _zb_levelColor.zb_all     = __data_core.xxpk_tools_logger_color_all;   // black

        _zb_formatter = [NSDateFormatter new];
    }
    return self;
}

/// send / store the formatted log message to the destination
/// returns the formatted log message for processing by inheriting method
/// and for unit tests (nil if error)
- (NSString *)zb_send:(ZBLogLevel)zb_level
               zb_msg:(NSString *)zb_msg
            zb_thread:(NSString *)zb_thread
              zb_file:(NSString *)zb_file
          zb_function:(NSString *)zb_function
              zb_line:(NSUInteger)zb_line
           zb_context:(id)zb_context {

    NSString *time = [self formatDate:__data_core.xxpk_tools_logger_formatter timeZone:nil];

    NSString *color = [self colorForLevel:zb_level];

    NSString *line = [NSString stringWithFormat:@"%lu", (unsigned long)zb_line];

    return [NSString stringWithFormat:__data_core.xxpk_tools_logger_format_file,color,time,zb_function,line,zb_msg];
}

// returns the string of a level
- (NSString *)levelWord:(ZBLogLevel)level {

    NSString *str = @"";

    switch (level) {
        case ZBLogLevelDebug: str = _zb_levelString.zb_debug; break;
        case ZBLogLevelInfo: str = _zb_levelString.zb_info; break;
        case ZBLogLevelWarning: str = _zb_levelString.zb_warning; break;
        case ZBLogLevelError: str = _zb_levelString.zb_error; break;
        case ZBLogLevelVerbose: str = _zb_levelString.zb_verbose; break;
        case ZBLogLevelAll: str = _zb_levelString.zb_all; break;
        default: break;
    }

    return str;
}

// returns color string for level
- (NSString *)colorForLevel:(ZBLogLevel)level {

    NSString *color = @"";

    switch (level) {
        case ZBLogLevelDebug: color = _zb_levelColor.zb_debug; break;
        case ZBLogLevelInfo: color = _zb_levelColor.zb_info; break;
        case ZBLogLevelWarning: color = _zb_levelColor.zb_warning; break;
        case ZBLogLevelError: color = _zb_levelColor.zb_error; break;
        case ZBLogLevelVerbose: color = _zb_levelColor.zb_verbose; break;
        case ZBLogLevelAll: color = _zb_levelColor.zb_all; break;
        default: break;
    }

    return color;
}

// returns the filename of a path
- (NSString *)fileNameOfFile:(NSString *)file {
    NSArray *fileParts = [file componentsSeparatedByString:@"/"];
    if (fileParts.lastObject) {
        return fileParts.lastObject;
    }
    return @"";
}

// returns the filename without suffix (= file ending) of a path
- (NSString *)fileNameWithoutSuffix:(NSString *)file {
    NSString *fileName = [self fileNameOfFile:file];

    if (![fileName isEqualToString:@""]) {
        NSArray *fileNameParts = [fileName componentsSeparatedByString:@"."];
        if (fileNameParts.firstObject) {
            return fileNameParts.firstObject;
        }
    }
    return @"";
}

/// returns a formatted date string
/// optionally in a given abbreviated timezone like "UTC"
- (NSString *)formatDate:(NSString *)dateFormat timeZone:(NSString *)timeZone {
    if (!timeZone) {
        _zb_formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:timeZone];
    }
    _zb_formatter.dateFormat = dateFormat;
    NSString *dateStr = [_zb_formatter stringFromDate:[NSDate new]];
    return dateStr;
}

/// returns a uptime string
- (NSString *)uptime {
    double interval = [[NSDate new] timeIntervalSinceDate:[NSDate new]];

    int hours = (int)interval / 3600;
    int minutes = (int)(interval / 60) - (int)(hours * 60);
    int seconds = (int)(interval) - ((int)(interval / 60) * 60);

    NSInteger x = 100000000;
    NSInteger y = interval * x;
    NSInteger z = y % x;
    int milliseconds = (float)z/100000000.0;

    return [NSString stringWithFormat:__data_core.xxpk_tools_logger_uptime_format, hours, minutes, seconds, milliseconds];
}

/// checks if level is at least minLevel or if a minLevel filter for that path does exist
/// returns boolean and can be used to decide if a message should be logged or not
- (BOOL)zb_shouldLevelBeLogged:(ZBLogLevel)zb_level
                       zb_path:(NSString *)zb_path
                   zb_function:(NSString *)zb_function
                    zb_message:(NSString *)zb_message {

    if (zb_level >= _zb_minLevel) {

//        NSLog(@"level >= minLevel");

        return YES;

    }else {

//        NSLog(@"level < minLevel");

        return NO;

    }
}

- (void)dealloc {
    #if !OS_OBJECT_USE_OBJC
    if (_zb_queue) {
        dispatch_release(_zb_queue);
    }
    #endif
}
@end

