//
//  MyAdServer.m
//  nochange
//
//  Created by mac on 2024/7/26.
//

#import <Foundation/Foundation.h>
#import <signal.h>
#import <execinfo.h>

#import "XSHelper.h"
#import "MyAdServer.h"
#import "XSPhoneConfig.h"
#import "XSPhoneInfo.h"



void pushAdTaskLog(AdTaskLogData *data) {
    NSDictionary *dic = @{
        @"taskId": data->taskId,
        @"title": data->title,
        @"message": data->message,
        @"idfa": data->idfa,
        @"appid": data->appid,
        @"adid": data->adid,
        @"level": @(data->level),
        @"ecpm": data->ecpm ? : @0.0,
        @"iphoneId": data->iphoneId,
        @"ipAddr": data->ipAddr
    };
    saveAdTaskLog(dic);
}

void saveAdTaskLog(NSDictionary *dic) {
    XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
    NSString *url = [config GetFullServerURL:@"ios/top_selection/push_ad_task_log"];
    NSString *json = [XSHelper dic2Json:dic];
    XSHttpHelper *http = [[XSHttpHelper alloc] init];
    [http doPOST:url json:json  withCallback:^(NSData *res) {
        NSLog(@"-ad log- push:\n %@", [XSHelper data2str:res]);
    } withError:^(NSError *err) {
        NSLog(@"XS- %@", err);
    }];
}

void getLowEcpm(LowEcpmCallback callback) {
    XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
    NSString *url = [NSString stringWithFormat:@"ios/top_selection/low_ecpm?iphoneId=%@", config.IPhoneName];
    NSLog(@"XS- getLowEcpm url %@", url);
    NSString *fullurl = [config GetFullServerURL:url];
    XSHttpHelper *http = [[XSHttpHelper alloc] init];
    [http doGET:fullurl withCallback:^(NSData *data) {
        if(data && ![data isEqual:[NSNull null]]) {
            NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
            NSLog(@"XS- getLowEcpm data %@", dic);
            NSNumber *ecpm = dic[@"data"];
            if (ecpm) {
                callback(ecpm);
            } else {
                callback(ecpm);
            }
        } else {
            callback(@(0.0001));
        }
    } withError:^(NSError *err) {
        callback(@(0.0001));
    }];
    
}

BOOL needAdContinue(NSString *appid, NSString *idfa, NSNumber *maxEcpm) {
    XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
    NSString *fullurl = [config GetFullServerURL: @"ios/top_selection/get_need_continue"];
    NSDictionary *postData = @{
        @"id": config.IPhoneName,
        @"appid": appid,
        @"idfa": idfa,
        @"maxEcpm": maxEcpm
    };
    XSHttpHelper *http = [[XSHttpHelper alloc] init];
    NSData *data = [http doPOST:fullurl json:[XSHelper dic2Json:postData]];
    if(data == nil || [data isEqual:[NSNull null]]) {
        return NO;
    }
    NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
    NSLog(@"XS- needAdContinue data %@", dic);
    return [dic[@"data"] isEqual:@(true)];
}


void getChangeInfo(NSString *idfa, ChangeDataSaveCallback callback, error_callback errorCallback) {
    XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
    NSString *url = [config GetFullServerURL:@"ios/top_selection/get_change_data_json"];
    XSHttpHelper *http = [[XSHttpHelper alloc] init];
    NSDictionary *dic = @{
        @"packageName": [config PackageName],
        @"washParam": @([config WashParam]),
    };
    NSString *json = [XSHelper dic2Json:dic];

    [http doPOST:url json:json withCallback:^(NSData *jsonData) {
        NSDictionary *data = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
        if (data && [data objectForKey:@"data"]) {
            NSDictionary *_data = data[@"data"];
            if(_data && ![_data isEqual:[NSNull null]]) {
                callback(_data);
            }
        } else {
            if(errorCallback) {
                errorCallback(nil);
            }
           
        }
    } withError:^(NSError *err) {
        NSLog(@"XS- log- get data: %@", err);
        if(errorCallback) {
            errorCallback(err);
        }

    }];
}

void _newgetChangeInfo(NSString *idfa, ChangeDataSaveCallback callback, error_callback errorCallback) {
    XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
    NSString *url = [config GetFullServerURL:[NSString stringWithFormat:@"ios/top_selection/change_data?id=%@&idfa=%@", [config IPhoneName], idfa ?: @""]];
    XSHttpHelper *http = [[XSHttpHelper alloc] init];
    [http doGET:url  withCallback:^(NSData *jsonData) {
        NSDictionary *data = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
        if (data && [data objectForKey:@"data"]) {
            NSString *aesData = data[@"data"];
            NSString *decData = @"";
            if(aesData && ![aesData isEqual:[NSNull null]] && ![aesData isEqual:@""]) {
                decData = [aesData aesDecrypt:AES_KEY iv:AES_IV];
            }
            // NSString *decData = [aesData aesDecrypt:AES_KEY iv:AES_IV];
            NSLog(@"XS- changeData: %@", decData);
            NSDictionary *dt = [XSHelper json2Dictionary:decData];
            callback(dt);
        } else {
            if(errorCallback) {
                errorCallback(nil);
            }
           
        }
    } withError:^(NSError *err) {
        NSLog(@"XS- log- get data: %@", err);
        if(errorCallback) {
            errorCallback(err);
        }
    }];
}

BOOL saveChangeDataFile(NSDictionary *data) {
    if (!data || ![data isKindOfClass:[NSDictionary class]]) {
        NSLog(@"Invalid data input");
        return NO;
    }
    
    @try {
        NSString *bundleId = @"org.xyzshell.NotNil";
        NSString *plistPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleId];
        
        // 使用同步锁保证线程安全
        @synchronized(NSFileManager.defaultManager) {
            NSMutableDictionary *tempDic = [NSMutableDictionary new];
            
            // 安全地遍历字典
            [data enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                if (![key isKindOfClass:[NSString class]]) return;
                
                if (obj == [NSNull null]) {
                    tempDic[key] = nil;
                } else if ([obj isKindOfClass:[NSDictionary class]]) {
                    NSMutableDictionary *newDic = [NSMutableDictionary new];
                    [(NSDictionary *)obj enumerateKeysAndObjectsUsingBlock:^(id key1, id obj1, BOOL *stop1) {
                        if (![key1 isKindOfClass:[NSString class]]) return;
                        newDic[key1] = (obj1 == [NSNull null]) ? nil : obj1;
                    }];
                    tempDic[key] = [newDic copy];
                } else {
                    tempDic[key] = obj;
                }
            }];
            
            // 创建目录
            NSError *error;
            NSString *dirPath = [plistPath stringByDeletingLastPathComponent];
            if (![NSFileManager.defaultManager fileExistsAtPath:dirPath]) {
                if (![NSFileManager.defaultManager createDirectoryAtPath:dirPath
                                           withIntermediateDirectories:YES
                                                          attributes:nil
                                                             error:&error]) {
                    NSLog(@"Failed to create directory: %@", error);
                    return NO;
                }
            }
            
            // 写入文件
            BOOL y = [tempDic writeToFile:plistPath atomically:YES];
            NSLog(@"XS- save change file: %@", @(y));
            return y;
        }
    } @catch (NSException *exception) {
        NSLog(@"Error saving change data: %@", exception);
        return NO;
    }
}

AdLoadInfo getAdLoadInfo(NSDictionary *request) {
    AdLoadInfo info = {0}; // 初始化所有字段为0
    
    if (!request || ![request isKindOfClass:[NSDictionary class]]) {
        NSLog(@"Invalid request");
        return info;
    }
    
    @try {
        NSString *apiUrl = [[XSPhoneConfig sharedInstance] GetFullServerURL:@"ios/top_selection/ad_can_show"];
        if (!apiUrl.length) {
            NSLog(@"Invalid API URL");
            return info;
        }
        
        XSHttpHelper *http = [[XSHttpHelper alloc] init];
        NSData *data = [http doPOST:apiUrl json:[XSHelper dic2Json:request]];
        
        if (!data) {
            NSLog(@"No response data");
            return info;
        }
        
        NSError *jsonError;
        NSDictionary *res = [NSJSONSerialization JSONObjectWithData:data
                                                          options:0
                                                            error:&jsonError];
        
        if (jsonError || ![res isKindOfClass:[NSDictionary class]]) {
            NSLog(@"JSON parsing error: %@", jsonError);
            return info;
        }
        
        NSDictionary *resData = res[@"data"];
        if (![resData isKindOfClass:[NSDictionary class]]) {
            NSLog(@"Invalid response data format");
            return info;
        }
        
        // 安全地获取值
        info.loads = [resData[@"loads"] isKindOfClass:[NSNumber class]] ? resData[@"loads"] : @0;
        info.adTime = [resData[@"adTime"] isKindOfClass:[NSNumber class]] ? resData[@"adTime"] : @0;
        info.adTimeout = [resData[@"adTimeout"] isKindOfClass:[NSNumber class]] ? resData[@"adTimeout"] : @0;
        info.adTouchAfterMs = [resData[@"adTouchAfterMs"] isKindOfClass:[NSNumber class]] ? resData[@"adTouchAfterMs"] : @0;
        info.adTouchBeforeMs = [resData[@"adTouchBeforeMs"] isKindOfClass:[NSNumber class]] ? resData[@"adTouchBeforeMs"] : @0;
        info.touchRate = [resData[@"touchRate"] isKindOfClass:[NSNumber class]] ? resData[@"touchRate"] : @0;
        
    } @catch (NSException *exception) {
        NSLog(@"Error getting ad load info: %@", exception);
    }
    
    return info;
}

void pushInfo(int type, NSString *data, rt_str_callback callback,error_callback errorCallback) {
    XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
    NSString *url = [config GetMainServerURL:@"ios/top_selection/_putinfo"];
    NSString *aesData = [data aesEncrypt:AES_KEY iv:AES_IV];
    NSDictionary *dic = @{
        @"data": aesData,
        @"type": @(type)
    };
    XSHttpHelper *http = [[XSHttpHelper alloc] init];
    [http doPOST:url json:[XSHelper dic2Json:dic] withCallback:^(NSData *data) {
        NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
        if (dic && dic[@"data"]) {
            NSString *strData = dic[@"data"];
            NSLog(@"XS- aes data:%@", strData);
            NSString *json = @"";
            if(strData && ![strData isEqual:[NSNull null]]) {
                json = [strData aesDecrypt:AES_KEY iv:AES_IV];
            }
            callback(json);
        }
    } withError:errorCallback];
}

void pushIphoneLog(NSString *data) {
    /*
     logs.ipAddr = log.ipAddr;
             logs.created = log.created;
             logs.data = log.decryptData();
             logs.type = log.type;
             logs.pkgName = log.pkgName;
             logs.version = log.version;
     */
    NSString *aesData = [data aesEncrypt:AES_KEY iv:AES_IV];
    NSString *ipAddr = [[XSPhoneInfo sharedInstance] IPAddress];
    NSString *pkgName =  [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
    NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
    NSDictionary *dic = @{
        @"ipAddr": ipAddr,
        @"data": aesData,
        @"type": @(2),
        @"pkgName": pkgName,
        @"version": version
    };

    XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
    NSString *url = [config GetMainServerURL:@"ios/top_selection/save_iphone_logs"];
    XSHttpHelper *http = [[XSHttpHelper alloc] init];
    [http doPOST:url json:[XSHelper dic2Json:dic] withCallback:^(NSData *data) {
        NSString *log = [XSHelper data2str:data];
        NSLog(@"pushIphoneLog %@", log);
    } withError:^(NSError *err) {
        NSLog(@"pushIphoneLog %@", err);
    }];
}

void logMessage(NSString *message) {
    NSString *documentsDirectory = @"/var/logs/";
    NSString *logFilePath = [documentsDirectory stringByAppendingPathComponent:@"app_log.txt"];
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *timestamp = [dateFormatter stringFromDate:[NSDate date]];
    
    NSString *logEntry = [NSString stringWithFormat:@"%@: %@\n", timestamp, message];
    
    if (![[NSFileManager defaultManager] fileExistsAtPath:logFilePath]) {
        [logEntry writeToFile:logFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
    } else {
        NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
        [fileHandle seekToEndOfFile];
        [fileHandle writeData:[logEntry dataUsingEncoding:NSUTF8StringEncoding]];
        [fileHandle closeFile];
    }
}


void uncaughtExceptionHandler(NSException *exception) {
    NSArray *callStack = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    
    NSString *urlString = [NSString stringWithFormat:@"crash://%@", name];
    NSString *userInfo = [NSString stringWithFormat:@"%@\nreason:\n%@\ncallStackSymbols:\n%@",
                          urlString, reason, [callStack componentsJoinedByString:@"\n"]];
    
    NSLog(@"Crash: %@", userInfo);
    logMessage(userInfo);
    // 这里你可以将崩溃信息保存到文件或发送到服务器
    pushIphoneLog(userInfo);
}

void signalHandler(int signal) {
    NSMutableString *crashLog = [NSMutableString string];
    [crashLog appendFormat:@"Signal %d was raised.\n", signal];
    
    void* callstack[128];
    int frames = backtrace(callstack, 128);
    char **strs = backtrace_symbols(callstack, frames);
    
    for (int i = 0; i < frames; ++i) {
        [crashLog appendFormat:@"%s\n", strs[i]];
    }
    
    free(strs);
    
    NSLog(@"Crash: %@", crashLog);
    logMessage(crashLog);
    // 这里你可以将崩溃信息保存到文件或发送到服务器
    
    pushIphoneLog(crashLog);
}

void registerSignalHandler(void) {
    signal(SIGABRT, signalHandler);
    signal(SIGILL, signalHandler);
    signal(SIGSEGV, signalHandler);
    signal(SIGFPE, signalHandler);
    signal(SIGBUS, signalHandler);
    signal(SIGPIPE, signalHandler);
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
}
