#import "SpeechPlugin.h"
#import <iflyMSC/iflyMSC.h>
#import "M4aToPcmHelper.h"
#import "Mp4ToPcmHelper.h"
#import "Results/ISEResult.h"
#import "Results/ISEResultXmlParser.h"
#import "Results/ISEResultTools.h"

@interface SpeechPlugin () <IFlySpeechEvaluatorDelegate, ISEResultXmlParserDelegate>
@property (nonatomic, strong) FlutterResult result;
@property (nonatomic, strong) IFlySpeechEvaluator *iFlySpeechEvaluator;
@property (nonatomic, strong) NSNumber *index;
@end

@implementation SpeechPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    FlutterMethodChannel* channel = [FlutterMethodChannel
                                     methodChannelWithName:@"speech_plugin"
                                     binaryMessenger:[registrar messenger]];
    SpeechPlugin* instance = [[SpeechPlugin alloc] init];
    [registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    self.result = result;
    if ([@"getPlatformVersion" isEqualToString:call.method]) {
        result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
    } else if ([@"initSpeechSdk" isEqualToString:call.method]) {
        [self iflyInit];
    }  else if ([@"evaluatorByAudio" isEqualToString:call.method]) {
        NSNumber* index = call.arguments[@"index"];
        NSString* recordPath = call.arguments[@"recordPath"];
        NSString* text = call.arguments[@"en"];
        [self evaluateVoice:index andPath:recordPath andText:text andIsVideo:false];
    }  else if ([@"evaluatorByMp4" isEqualToString:call.method]) {
        NSNumber* index = call.arguments[@"index"];
        NSString* recordPath = call.arguments[@"recordPath"];
        NSString* text = call.arguments[@"en"];
        [self evaluateVoice:index andPath:recordPath andText:text andIsVideo:true];
    } else {
        result(FlutterMethodNotImplemented);
    }
}

#pragma mark - Bridge Actions

- (void)iflyInit {
    [IFlySpeechUtility createUtility:@"appid=5db7af6b"];
    self.iFlySpeechEvaluator = [IFlySpeechEvaluator sharedInstance];
    self.iFlySpeechEvaluator.delegate = self;
    [self configEvaluator];
}

- (void) configEvaluator {
    [self.iFlySpeechEvaluator setParameter:@"" forKey:[IFlySpeechConstant PARAMS]];
    [self.iFlySpeechEvaluator setParameter:@"read_sentence" forKey:[IFlySpeechConstant ISE_CATEGORY]];
    [self.iFlySpeechEvaluator setParameter:@"en_us" forKey:[IFlySpeechConstant LANGUAGE]];
    [self.iFlySpeechEvaluator setParameter:@"5000" forKey:[IFlySpeechConstant VAD_BOS]];
    [self.iFlySpeechEvaluator setParameter:@"1800" forKey:[IFlySpeechConstant VAD_EOS]];
    [self.iFlySpeechEvaluator setParameter:@"-1" forKey:[IFlySpeechConstant SPEECH_TIMEOUT]];
    [self.iFlySpeechEvaluator setParameter:@"complete" forKey:[IFlySpeechConstant ISE_RESULT_LEVEL]];
    [self.iFlySpeechEvaluator setParameter:@"16000" forKey:[IFlySpeechConstant SAMPLE_RATE]];
    [self.iFlySpeechEvaluator setParameter:@"xml" forKey:[IFlySpeechConstant ISE_RESULT_TYPE]];
    [self.iFlySpeechEvaluator setParameter:@"-1" forKey:@"audio_source"];
}

- (void) evaluateVoice: (NSNumber*)index andPath:(NSString*)path andText:(NSString*)text andIsVideo:(BOOL) isVideo
{
    self.index = index;
    if(isVideo) {
        [Mp4ToPcmHelper Mp4ToPcmWithUrl:[[NSURL alloc] initFileURLWithPath:path] completion:^(NSData *data) {
            if(data == nil) {
                self.result([NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]);
                return;
            }
            NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
            NSMutableData *buffer= [NSMutableData dataWithData:[text dataUsingEncoding:encoding]];
            [self.iFlySpeechEvaluator startListening:buffer params:nil];
            [self.iFlySpeechEvaluator writeAudio:data];
            [self.iFlySpeechEvaluator stopListening];
        }];
    } else {
        NSData *voiceData = [M4aToPcmHelper M4aToPcmWithUrl:[[NSURL alloc] initFileURLWithPath:path]];
        if(voiceData == nil) {
            self.result([NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]);
            return;
        }
        NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
        NSMutableData *buffer= [NSMutableData dataWithData:[text dataUsingEncoding:encoding]];
        [self.iFlySpeechEvaluator startListening:buffer params:nil];
        [self.iFlySpeechEvaluator writeAudio:voiceData];
        [self.iFlySpeechEvaluator stopListening];
    }
}

#pragma mark - iFly delegate

// 评测结果回调
- (void)onResults:(NSData *)results isLast:(BOOL)isLast {
    if (isLast) {
        if(results) {
            const char* chResult = [results bytes];
            NSString* strResults = nil;
            NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
            strResults = [[NSString alloc] initWithBytes:chResult length:[results length] encoding:encoding];
            if(strResults != nil) {
                ISEResultXmlParser *parser = [ISEResultXmlParser alloc];
                [parser setDelegate:self];
                [parser parserXml:strResults];
            } else {
                self.result([NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]);
            }
        } else {
            self.result([NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]);
        }
    }
}

- (void)onCompleted:(IFlySpeechError *)errorCode {
    if (errorCode.errorCode != 0) {
        self.result([NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]);
    }
}

- (void)onCancel {}

- (void)onBeginOfSpeech {}

- (void)onEndOfSpeech {}

- (void)onVolumeChanged:(int)volume buffer:(NSData *)buffer {}


#pragma mark - ISEResultXmlParser delegate

-(void)onISEResultXmlParser:(NSXMLParser *)parser Error:(NSError*)error {
    if (error.code != 0) {
        self.result([NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]);
    }
}

-(void)onISEResultXmlParserResult:(ISEResult*)result {
    if (result.is_rejected) {
        self.result([NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]);
    } else {
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setValue:self.index forKey:@"index"];
        [dic setValue:@(result.total_score) forKey:@"score"];
        NSString* words = [ISEResultTools formatDetailsForLanguageEN: result.sentences];
        [dic setValue:words forKey:@"words"];
        self.result(dic);
    }
}

@end
