//
//  SLNuiSpeechRecognizer.m
//  SLAiELTS
//
//  Created by Gusont on 2023/3/6.
//

#import "SLNuiSpeechRecognizer.h"
#import <nuisdk/NeoNuiTts.h>
#import "NLSPlayAudio.h"
#import "NuiSdkUtils.h"
#import <nuisdk/NeoNui.h>
#import "NLSVoiceRecorder.h"


#import <AdSupport/ASIdentifierManager.h>

static BOOL save_log = YES;//不加无法保存
static BOOL save_wav = YES;

@interface SLNuiSpeechRecognizer()<NeoNuiSdkDelegate, NlsVoiceRecorderDelegate, NlsPlayerDelegate>

@property(nonatomic,strong) NeoNui* nui;

@property(nonatomic,strong) NlsVoiceRecorder *voiceRecorder;

@property(nonatomic,strong) NSMutableData *recordedVoiceData;

@property(nonatomic,strong) NuiSdkUtils *utils;

@property(nonatomic,strong) NLSPlayAudio *voicePlayer;

@property (nonatomic, strong) NSString *recorderStartTime;

@property (nonatomic, assign) BOOL isSaveVoice;
@end

@implementation SLNuiSpeechRecognizer

- (instancetype)init {
    self = [super init];
    if (self) {
        [self confignSpeechRecognizer];
    }
    return self;
}
-(void)dealloc{
    TLog(@"%s",__FUNCTION__);
    [_nui nui_release];
}

- (void)confignSpeechRecognizer {
    
    _voicePlayer = [[NLSPlayAudio alloc] init];
    _voicePlayer.delegate = self;
    
    _voiceRecorder = [[NlsVoiceRecorder alloc] init];
    _voiceRecorder.delegate = self;

    [SLAuthorizationManager requestAuthorization:YMAuthorizationTypeMicrophone grantedBlock:^(BOOL granted) {
            
    }];
    _utils = [[NuiSdkUtils alloc] init];
    [self initNui];
}

- (void)initNui {
    if (_nui == NULL) {
        _nui = [NeoNui get_instance];
        _nui.delegate = self;
    }
    //请注意此处的参数配置，其中账号相关需要在Utils.m getTicket 方法中填入后才可访问服务
    NSString * initParam = [self genInitParams];
    
    [_nui nui_initialize:[initParam UTF8String] logLevel:LOG_LEVEL_ERROR saveLog:save_log];
    NSString * parameters = [self genParams];
    [_nui nui_set_params:[parameters UTF8String]];
}

#pragma mark - 清除文件缓存
- (void)clearCacheWithFilePath:(NSString *)path {
    
    //拿到path路径的下一级目录的子文件夹
    NSArray *subPathArr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
    NSString *filePath = nil;
    
    NSError *error = nil;
    for (NSString *subPath in subPathArr)
    {
        filePath = [path stringByAppendingPathComponent:subPath];
        NSArray *subFilePathArr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:filePath error:nil];
        if (subFilePathArr.count) {
            [self clearCacheWithFilePath:filePath];
        }else {
            if (![filePath containsString:@"origin_0"]) {
                //删除子文件夹
                [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
            }
        }
    }
}

-(NSString*) genInitParams {
    NSString *strResourcesBundle = [[NSBundle mainBundle] pathForResource:@"Resources" ofType:@"bundle"];
    NSString *bundlePath = [[NSBundle bundleWithPath:strResourcesBundle] resourcePath];
    NSString *id_string = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
    NSString *debug_path = [_utils createDir];

    dispatch_async(dispatch_queue_create("sl.nuispeech.voices.file", DISPATCH_QUEUE_CONCURRENT), ^{
        [self clearCacheWithFilePath:debug_path];
    });
    
    
    NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
    
    [dictM setObject:bundlePath forKey:@"workspace"];
    [dictM setObject:debug_path forKey:@"debug_path"];
    [dictM setObject:id_string forKey:@"device_id"];
    [dictM setObject:save_wav ? @"true" : @"false" forKey:@"save_wav"];
    
    //从阿里云获取appkey和token进行语音服务访问
    [dictM setObject:SLNuisdkAppKey forKey:@"app_key"];
//    [dictM setObject:SLNuisdkToken forKey:@"token"];

    //由于token 24小时过期，可以参考getTicket实现从阿里云服务动态获取
    [_utils getTicket:dictM];
    [dictM setObject:@"wss://nls-gateway.cn-shanghai.aliyuncs.com:443/ws/v1" forKey:@"url"];
    
    NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
    NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    return jsonStr;
}

-(NSString*) genParams {
    NSMutableDictionary *nls_config = [NSMutableDictionary dictionary];
    [nls_config setValue:@YES forKey:@"enable_intermediate_result"];
//    参数可根据实际业务进行配置
//    [nls_config setValue:@true forKey:@"enable_punctuation_prediction"];
//    [nls_config setValue:@true forKey:@"enable_inverse_text_normalization"];
//    [nls_config setValue:@true forKey:@"enable_voice_detection"];
//    [nls_config setValue:@10000 forKey:@"max_start_silence"];
//    [nls_config setValue:@800 forKey:@"max_end_silence"];
//    [nls_config setValue:@16000 forKey:@"sample_rate"];
//    [nls_config setValue:@"opus" forKey:@"sr_format"];
    NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
    [dictM setObject:nls_config forKey:@"nls_config"];
    [dictM setValue:@(SERVICE_TYPE_ASR) forKey:@"service_type"];
//    如果有HttpDns则可进行设置
//    [dictM setObject:[_utils getDirectIp] forKey:@"direct_ip"];
    
    NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
    NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    return jsonStr;
}


#pragma mark - ------语音识别------

- (void)startSpeechRecognizer {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyyMMdd_HHmmss"];
    NSDate *datenow = [NSDate date];
    NSString *currentTimeString = [formatter stringFromDate:datenow];
    self.recorderStartTime = currentTimeString;
    NSLog(@"currentTimeString----%@",currentTimeString);
    self.recordedVoiceData = nil;
    dispatch_async(dispatch_get_main_queue(), ^{
        if (_nui != nil) {
            [_nui nui_dialog_start:MODE_P2T dialogParam:NULL];
        } else {
            TLog(@"in StartButHandler no nui alloc");
        }
    });
}

- (void)stopSpeechRecognizer:(BOOL)isSaveVoice {
    self.isSaveVoice = isSaveVoice;
    if (_nui != nil) {
        [_nui nui_dialog_cancel:NO];
        [_voiceRecorder stop:YES];
    } else {
        TLog(@"in StopButHandler no nui alloc");
    }
}

#pragma mark - Nui Listener
-(void)onNuiEventCallback:(NuiCallbackEvent)nuiEvent
                   dialog:(long)dialog
                kwsResult:(const char *)wuw
                asrResult:(const char *)asr_result
                 ifFinish:(bool)finish
                  retCode:(int)code {
    TLog(@"onNuiEventCallback event %d finish %d", nuiEvent, finish);
    if (nuiEvent == EVENT_ASR_PARTIAL_RESULT || nuiEvent == EVENT_ASR_RESULT) {
        TLog(@"ASR RESULT %s finish %d", asr_result, finish);
        NSString *result = [NSString stringWithUTF8String:asr_result];
        NSDictionary *dict = [result mj_JSONObject];
        NSDictionary *payloadDict = [dict objectForKey:@"payload"];
        if (finish && self.recognizerResultBlock && self.isSaveVoice) {
            NSString *voicePath = [_utils createDir];
            voicePath = [voicePath stringByAppendingFormat:@"/%@/origin_0.wav", self.recorderStartTime];
            self.recognizerResultBlock([payloadDict objectForKey:@"result"] ?: @"", voicePath);
        }
    }
    else if (nuiEvent == EVENT_ASR_ERROR) {
        TLog(@"EVENT_ASR_ERROR error[%d]", code);
    } else if (nuiEvent == EVENT_MIC_ERROR) {
        TLog(@"MIC ERROR");
        [_voiceRecorder stop:true];
        [_voiceRecorder start];
    }
//
    //finish 为真（可能是发生错误，也可能是完成识别）表示一次任务生命周期结束，可以开始新的识别
    if (finish) {
        
    }
    return;
}

-(int)onNuiNeedAudioData:(char *)audioData length:(int)len {
    TLog(@"onNuiNeedAudioData");
    static int emptyCount = 0;
    @autoreleasepool {
        @synchronized(_recordedVoiceData){
            if (_recordedVoiceData.length > 0) {
                int recorder_len = 0;
                if (_recordedVoiceData.length > len)
                    recorder_len = len;
                else
                    recorder_len = _recordedVoiceData.length;
                NSData *tempData = [_recordedVoiceData subdataWithRange:NSMakeRange(0, recorder_len)];
                [tempData getBytes:audioData length:recorder_len];
                tempData = nil;
                NSInteger remainLength = _recordedVoiceData.length - recorder_len;
                NSRange range = NSMakeRange(recorder_len, remainLength);
                [_recordedVoiceData setData:[_recordedVoiceData subdataWithRange:range]];
                emptyCount = 0;
                return recorder_len;
            } else {
                if (emptyCount++ >= 50) {
                    TLog(@"_recordedVoiceData length = %lu! empty 50times.", (unsigned long)_recordedVoiceData.length);
                    emptyCount = 0;
                }
                return 0;
            }

        }
    }
    return 0;
}
-(void)onNuiAudioStateChanged:(NuiAudioState)state {
    TLog(@"onNuiAudioStateChanged state=%u", state);
    if (state == STATE_CLOSE || state == STATE_PAUSE) {
        [_voiceRecorder stop:YES];
    } else if (state == STATE_OPEN){
        self.recordedVoiceData = [NSMutableData data];
        [_voiceRecorder start];
    }
}

-(void)onNuiRmsChanged:(float)rms {
    TLog(@"onNuiRmsChanged rms=%f", rms);
}


- (void)recorderDidStart {
    TLog(@"recorderDidStart");
}

- (void)recorderDidStop {
    [self.recordedVoiceData setLength:0];
}

- (void)voiceDidFail:(NSError *)error {
    TLog(@"recorder error ");
}

- (void)voiceRecorded:(NSData *)frame {
    @synchronized(_recordedVoiceData){
        [_recordedVoiceData appendData:frame];
    }
}

- (void)playerDidFinish {
    NSLog(@"----->>>playerDidFinish");
}

@end
