//
//  ZBFileDestination.m
//  ZBObjectiveCBeaver
//
//  Created by Jumbo on 2021/3/16.
//

#import "ZBFileDestination.h"
#import "XXGPlayKitConfig.h"
#import "NSData+SunHope.h"

@interface ZBFileDestination() {
    NSURL *_zb_logFileURL;
    BOOL _zb_syncAfterEachWrite;
    NSInteger _maxDays;
    NSDateFormatter *_dateFormatter;
    BOOL _encryptionEnabled;
}

@end

@implementation ZBFileDestination

- (instancetype)init
{
    self = [super init];
    if (self) {
        _zb_syncAfterEachWrite = NO;
        _maxDays = 7;
        _encryptionEnabled = NO;

        _dateFormatter = [[NSDateFormatter alloc] init];
        _dateFormatter.dateFormat = __data_core.xxpk_tools_logger_file_date_format;

        if (!_zb_logFileURL) {
            NSURL *baseURL = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask].firstObject;
            _zb_logFileURL = [baseURL URLByAppendingPathComponent:NSStringFromClass(self.class) isDirectory:YES];
        }
    }
    return self;
}

// platform-dependent logfile directory default
- (instancetype)initWithLogFileURL:(NSURL *)zb_url
{
    self = [super init];
    if (self) {
        self.zb_logFileURL = zb_url;
    }
    return self;
}

// append to file. uses full base class functionality
- (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];

    NSString *formattedString = [NSString stringWithFormat:__data_core.xxpk_tools_logger_format_file,color,time,zb_function,line,zb_msg];

    if (![formattedString isEqualToString:@""]) {
        NSURL *currentFile = [self currentLogFileURL];
        [self zb_saveToFile:formattedString fileURL:currentFile];
    }

    return formattedString;
}

// appends a string as line to a file.
// returns boolean about success
- (BOOL)zb_saveToFile:(NSString *)zb_str {
    return [self zb_saveToFile:zb_str fileURL:_zb_logFileURL];
}

- (BOOL)zb_saveToFile:(NSString *)zb_str fileURL:(NSURL *)fileURL {
    if (!fileURL) {
        return NO;
    }

    NSString *line = zb_str;

    // 如果启用了加密，对数据进行加密
    if (_encryptionEnabled) {
        NSData *originalData = [line dataUsingEncoding:NSUTF8StringEncoding];
        if (!originalData) {
            return NO;
        }

        NSData *encryptedData = [originalData ___xxpk_encryptWithRandomIV];
        if (!encryptedData) {
            NSLog(@"Failed to encrypt log data");
            return NO;
        }

        // 将加密数据转换为Base64字符串存储
        line = [encryptedData base64EncodedStringWithOptions:0];
    }

    // 添加换行符
    line = [line stringByAppendingString:@"\n"];
    NSData *data = [line dataUsingEncoding:NSUTF8StringEncoding];
    if (!data) {
        return NO;
    }

    return [self zb_write:data zb_to:fileURL];
}

- (BOOL)zb_write:(NSData *)zb_data zb_to:(NSURL *)zb_url {
    __block BOOL zb_success = NO;
    NSFileCoordinator *zb_coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
    NSError *zb_error = nil;
    [zb_coordinator coordinateWritingItemAtURL:zb_url options:0 error:&zb_error byAccessor:^(NSURL * _Nonnull zb_newURL) {

        NSError *zb_error = nil;

        if (![[NSFileManager defaultManager] fileExistsAtPath:zb_url.path]) {

            NSURL *zb_directoryURL = zb_url.URLByDeletingLastPathComponent;
            if (![[NSFileManager defaultManager] fileExistsAtPath:zb_directoryURL.path]) {
                [[NSFileManager defaultManager] createDirectoryAtURL:zb_directoryURL withIntermediateDirectories:YES attributes:nil error:&zb_error];
            }

            [[NSFileManager defaultManager] createFileAtPath:zb_url.path contents:nil attributes:nil];
        }

        NSFileHandle *zb_fileHandle = [NSFileHandle fileHandleForWritingToURL:zb_url error:&zb_error];
        [zb_fileHandle seekToEndOfFile];
        [zb_fileHandle writeData:zb_data];
        if (_zb_syncAfterEachWrite) {
            [zb_fileHandle synchronizeFile];
        }
        [zb_fileHandle closeFile];

        if (zb_error) {
            NSLog(@"Failed writing file with error:%@", zb_error.description);
        }else {
            zb_success = YES;
        }

    }];

    if (zb_error) {
        NSLog(@"Failed writing file with error:%@", zb_error.description);
    }

    return zb_success;
}

- (NSURL *)zb_logFileURL {
    return _zb_logFileURL;
}

- (void)setZb_logFileURL:(NSURL *)zb_logFileURL {
    _zb_logFileURL = zb_logFileURL;
}

- (BOOL)zb_syncAfterEachWrite {
    return _zb_syncAfterEachWrite;
}

- (void)setZb_syncAfterEachWrite:(BOOL)zb_syncAfterEachWrite {
    _zb_syncAfterEachWrite = zb_syncAfterEachWrite;
}

#pragma mark - New Properties


- (NSInteger)maxDays {
    return _maxDays;
}

- (void)setMaxDays:(NSInteger)maxDays {
    _maxDays = maxDays;
}

- (BOOL)encryptionEnabled {
    return _encryptionEnabled;
}

- (void)setEncryptionEnabled:(BOOL)encryptionEnabled {
    _encryptionEnabled = encryptionEnabled;
}

#pragma mark - New Methods

- (NSURL *)currentLogFileURL {
    NSString *dateString = [_dateFormatter stringFromDate:[NSDate date]];
    return [_zb_logFileURL URLByAppendingPathComponent:dateString];
}

- (NSArray<NSURL *> *)allLogFiles {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;

    if (![fileManager fileExistsAtPath:_zb_logFileURL.path]) {
        return @[];
    }

    NSArray *logFiles = [fileManager contentsOfDirectoryAtURL:_zb_logFileURL
                                includingPropertiesForKeys:@[NSURLCreationDateKey]
                                                   options:NSDirectoryEnumerationSkipsHiddenFiles
                                                     error:&error];
    if (error) {
        NSLog(@"Error reading log directory: %@", error);
        return @[];
    }

    return [logFiles sortedArrayUsingComparator:^NSComparisonResult(NSURL *url1, NSURL *url2) {
        NSDate *date1, *date2;
        [url1 getResourceValue:&date1 forKey:NSURLCreationDateKey error:nil];
        [url2 getResourceValue:&date2 forKey:NSURLCreationDateKey error:nil];
        return [date2 compare:date1]; // 新的在前
    }];
}

- (NSString *)readLogFile:(NSURL *)fileURL {
    NSError *error;

    // 读取文件内容
    NSString *fileContent = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error];
    if (error || !fileContent) {
        NSLog(@"Error reading log file: %@", error);
        return @"";
    }

    // 如果启用了加密，需要按行解密
    if (_encryptionEnabled) {
        NSMutableString *allContent = [NSMutableString string];

        // 按行分割
        NSArray *lines = [fileContent componentsSeparatedByString:@"\n"];

        for (NSString *line in lines) {
            // 跳过空行
            if (line.length == 0) {
                continue;
            }

            // 将Base64字符串转换为NSData
            NSData *encryptedData = [[NSData alloc] initWithBase64EncodedString:line options:0];
            if (!encryptedData) {
                NSLog(@"Failed to decode base64 line: %@", line);
                continue;
            }

            // 解密数据
            NSData *decryptedData = [encryptedData __xxpk_decryptDataWithRandomIV];
            if (!decryptedData) {
                NSLog(@"Failed to decrypt log line");
                continue;
            }

            // 转换为字符串
            NSString *decryptedLine = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
            if (decryptedLine) {
                [allContent appendString:decryptedLine];
                [allContent appendString:@"\n"];
            } else {
                NSLog(@"Failed to convert decrypted data to string");
            }
        }

        return allContent;
    } else {
        // 未加密的情况，直接返回
        return fileContent;
    }
}

- (NSString *)readAllLogs {
    NSArray *logFiles = [self allLogFiles];
    NSMutableString *allContent = [NSMutableString string];

    for (NSURL *fileURL in logFiles) {
        NSString *content = [self readLogFile:fileURL];
        if (content.length > 0) {
            [allContent appendFormat:__data_core.xxpk_tools_logger_file_separator, fileURL.lastPathComponent];
            [allContent appendString:content];
            [allContent appendString:@"\n"];
        }
    }

    return allContent;
}

- (NSString *)readAllLogsRaw {
    NSArray *logFiles = [self allLogFiles];
    NSMutableString *allContent = [NSMutableString string];

    for (NSURL *fileURL in logFiles) {
        // 直接读取文件内容，不进行解密
        NSError *error;
        NSString *fileContent = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error];
        if (error || !fileContent) {
            NSLog(@"Error reading raw log file: %@", error);
            continue;
        }

        if (fileContent.length > 0) {
            [allContent appendFormat:__data_core.xxpk_tools_logger_file_separator, fileURL.lastPathComponent];
            [allContent appendString:fileContent];
            [allContent appendString:@"\n"];
        }
    }

    return allContent;
}

- (NSString *)readLogsForDate:(NSDate *)date {
    if (!date) {
        return @"";
    }

    NSString *dateString = [_dateFormatter stringFromDate:date];
    NSURL *fileURL = [_zb_logFileURL URLByAppendingPathComponent:dateString];

    return [self readLogFile:fileURL];
}

- (NSArray<NSDate *> *)allLogDates {
    NSMutableArray *dates = [NSMutableArray array];
    NSArray *logFiles = [self allLogFiles];

    for (NSURL *fileURL in logFiles) {
        NSString *fileName = fileURL.lastPathComponent;
        // 文件名就是日期字符串：yyyy-MM-dd
        NSDate *date = [_dateFormatter dateFromString:fileName];
        if (date) {
            [dates addObject:date];
        }
    }

    // 按日期降序排序（最新的在前面）
    [dates sortUsingComparator:^NSComparisonResult(NSDate *date1, NSDate *date2) {
        return [date2 compare:date1];
    }];

    return dates;
}

- (void)cleanupOldLogs {
    if (_maxDays <= 0) return;

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *logFiles = [self allLogFiles];
    NSDate *cutoffDate = [NSDate dateWithTimeIntervalSinceNow:-_maxDays * 24 * 60 * 60];

    for (NSURL *fileURL in logFiles) {
        NSDate *creationDate;
        [fileURL getResourceValue:&creationDate forKey:NSURLCreationDateKey error:nil];

        if (creationDate && [creationDate compare:cutoffDate] == NSOrderedAscending) {
            NSError *error;
            [fileManager removeItemAtURL:fileURL error:&error];
            if (error) {
                NSLog(@"Error deleting old log file: %@", error);
            }
        }
    }
}

@end
