/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

#import "CDVAudioRecorder.h"
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

@implementation CDVAudioRecorder

- (void)pluginInitialize {
    [super pluginInitialize];
    
    // Get shared audio session
    self.audioSession = [AVAudioSession sharedInstance];
    
    self.isRecording = NO;
    self.isPaused = NO;
}



- (void)sendErrorResult:(CDVInvokedUrlCommand*)command withMessage:(NSString*)message {
    // Ensure we're on the main thread for UI operations
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self sendErrorResult:command withMessage:message];
        });
        return;
    }
    
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR 
                                                messageAsString:message];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void)sendSuccessResult:(CDVInvokedUrlCommand*)command withMessage:(NSString*)message {
    // Ensure we're on the main thread for UI operations
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self sendSuccessResult:command withMessage:message];
        });
        return;
    }
    
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK 
                                                messageAsString:message];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

#pragma mark - Permission Handling

- (void)checkMicrophonePermission:(void(^)(BOOL granted))completion {
    // Get current permission status
    AVAudioSessionRecordPermission permission = [self.audioSession recordPermission];
    
    if (permission == AVAudioSessionRecordPermissionGranted) {
        completion(YES);
    } else if (permission == AVAudioSessionRecordPermissionDenied) {
        completion(NO);
    } else { // AVAudioSessionRecordPermissionUndetermined
        // Request permission
        [self.audioSession requestRecordPermission:^(BOOL granted) {
            // Always dispatch to main thread for UI operations
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(granted);
            });
        }];
    }
}

#pragma mark - Public Methods

- (void)startRecording:(CDVInvokedUrlCommand*)command {
    self.currentCommand = command;
    
    // Check permission first
    [self checkMicrophonePermission:^(BOOL granted) {
        if (!granted) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self sendErrorResult:command withMessage:@"Microphone permission not granted"];
            });
            return;
        }
        
        // Ensure we're on the main thread for UI operations
        dispatch_async(dispatch_get_main_queue(), ^{
            [self startRecordingInternal:command];
        });
    }];
}

- (void)stopRecording:(CDVInvokedUrlCommand*)command {
    if (!self.isRecording) {
        [self sendErrorResult:command withMessage:@"No recording in progress"];
        return;
    }
    
    // Ensure we're on the main thread for UI operations
    dispatch_async(dispatch_get_main_queue(), ^{
        [self stopRecordingInternal:command];
    });
}

- (void)pauseRecording:(CDVInvokedUrlCommand*)command {
    if (!self.isRecording || self.isPaused) {
        [self sendErrorResult:command withMessage:@"No active recording to pause"];
        return;
    }
    
    // Ensure audio operations happen on main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([self.audioRecorder respondsToSelector:@selector(pause)]) {
            [self.audioRecorder pause];
            self.isPaused = YES;
            [self sendSuccessResult:command withMessage:@"Recording paused"];
        } else {
            [self sendErrorResult:command withMessage:@"Pause not supported"];
        }
    });
}

- (void)resumeRecording:(CDVInvokedUrlCommand*)command {
    if (!self.isRecording || !self.isPaused) {
        [self sendErrorResult:command withMessage:@"No paused recording to resume"];
        return;
    }
    
    // Ensure audio operations happen on main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([self.audioRecorder respondsToSelector:@selector(record)]) {
            [self.audioRecorder record];
            self.isPaused = NO;
            [self sendSuccessResult:command withMessage:@"Recording resumed"];
        } else {
            [self sendErrorResult:command withMessage:@"Resume not supported"];
        }
    });
}

- (void)getRecordingState:(CDVInvokedUrlCommand*)command {
    NSString *state;
    if (self.isRecording) {
        state = self.isPaused ? @"paused" : @"recording";
    } else {
        state = @"stopped";
    }
    
    NSDictionary *resultDict = @{
        @"state": state,
        @"isRecording": @(self.isRecording),
        @"isPaused": @(self.isPaused)
    };
    
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK 
                                                messageAsDictionary:resultDict];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void)convertToBlob:(CDVInvokedUrlCommand*)command {
    if (!self.recordingFilePath || ![[NSFileManager defaultManager] fileExistsAtPath:self.recordingFilePath]) {
        [self sendErrorResult:command withMessage:@"No recorded file found"];
        return;
    }
    
    NSLog(@"Converting file to blob: %@", self.recordingFilePath);
    [self convertFileToBlob:command];
}

- (void)requestPermission:(CDVInvokedUrlCommand*)command {
    [self checkMicrophonePermission:^(BOOL granted) {
        NSString *status = granted ? @"granted" : @"denied";
        [self sendSuccessResult:command withMessage:status];
    }];
}

- (void)checkPermission:(CDVInvokedUrlCommand*)command {
    [self checkMicrophonePermission:^(BOOL granted) {
        NSString *status = granted ? @"granted" : @"denied";
        [self sendSuccessResult:command withMessage:status];
    }];
}

#pragma mark - Private Methods

- (void)startRecordingInternal:(CDVInvokedUrlCommand*)command {
    NSDictionary *options = [command.arguments objectAtIndex:0];
    
    // Ensure we're on the main thread for all operations
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self startRecordingInternal:command];
        });
        return;
    }
    
    // Configure audio session
    Class audioSessionClass = NSClassFromString(@"AVAudioSession");
    if (!audioSessionClass) {
        NSLog(@"❌ AVAudioSession class not available");
        [self sendErrorResult:command withMessage:@"AVAudioSession not available"];
        return;
    }
    
    NSLog(@"✅ AVAudioSession class found: %@", audioSessionClass);
    
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    id audioSession = [audioSessionClass performSelector:NSSelectorFromString(@"sharedInstance")];
    #pragma clang diagnostic pop
    
    if (!audioSession) {
        NSLog(@"❌ Failed to get AVAudioSession shared instance");
        [self sendErrorResult:command withMessage:@"Failed to get AVAudioSession shared instance"];
        return;
    }
    
    NSLog(@"✅ Audio session obtained: %@", audioSession);
    
    // Set category with error handling
    NSLog(@"Setting audio session category...");
    SEL setCategorySelector = NSSelectorFromString(@"setCategory:error:");
    if ([audioSession respondsToSelector:setCategorySelector]) {
        NSLog(@"✅ Audio session responds to setCategory:error:");
        
        NSMethodSignature *signature = [audioSession methodSignatureForSelector:setCategorySelector];
        if (signature) {
            NSLog(@"✅ Method signature obtained for setCategory");
            
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
            [invocation setSelector:setCategorySelector];
            
            NSString *category = @"AVAudioSessionCategoryPlayAndRecord";
            NSError *error = nil;
            
            NSLog(@"Setting category to: %@", category);
            
            [invocation setArgument:&category atIndex:2];
            [invocation setArgument:&error atIndex:3];
            
            [invocation invokeWithTarget:audioSession];
            
            if (error) {
                NSLog(@"❌ Failed to set audio session category: %@", error.localizedDescription);
                [self sendErrorResult:command withMessage:[NSString stringWithFormat:@"Failed to set audio session category: %@", error.localizedDescription]];
                return;
            } else {
                NSLog(@"✅ Audio session category set successfully");
            }
        } else {
            NSLog(@"❌ Failed to get method signature for setCategory");
        }
    } else {
        NSLog(@"❌ Audio session does not respond to setCategory:error:");
    }
    
    // Activate session with error handling
    NSLog(@"Activating audio session...");
    SEL setActiveSelector = NSSelectorFromString(@"setActive:error:");
    if ([audioSession respondsToSelector:setActiveSelector]) {
        NSLog(@"✅ Audio session responds to setActive:error:");
        
        NSMethodSignature *signature = [audioSession methodSignatureForSelector:setActiveSelector];
        if (signature) {
            NSLog(@"✅ Method signature obtained for setActive");
            
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
            [invocation setSelector:setActiveSelector];
            
            BOOL active = YES;
            NSError *error = nil;
            
            NSLog(@"Setting active to: %@", active ? @"YES" : @"NO");
            
            [invocation setArgument:&active atIndex:2];
            [invocation setArgument:&error atIndex:3];
            
            [invocation invokeWithTarget:audioSession];
            
            // Check if activation was successful
            SEL isOtherAudioPlayingSelector = NSSelectorFromString(@"isOtherAudioPlaying");
            if ([audioSession respondsToSelector:isOtherAudioPlayingSelector]) {
                #pragma clang diagnostic push
                #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                BOOL isActive = ![audioSession performSelector:isOtherAudioPlayingSelector];
                #pragma clang diagnostic pop
                NSLog(@"Audio session active status: %@", isActive ? @"YES" : @"NO");
                
                if (!isActive) {
                    NSLog(@"❌ Audio session activation failed");
                    [self sendErrorResult:command withMessage:@"Failed to activate audio session"];
                    return;
                }
            }
            
            if (error) {
                NSLog(@"❌ Failed to activate audio session: %@", error.localizedDescription);
                [self sendErrorResult:command withMessage:[NSString stringWithFormat:@"Failed to activate audio session: %@", error.localizedDescription]];
                return;
            } else {
                NSLog(@"✅ Audio session activated successfully");
            }
        } else {
            NSLog(@"❌ Failed to get method signature for setActive");
        }
    } else {
        NSLog(@"❌ Audio session does not respond to setActive:error:");
    }
    
    // Create recording file path
    NSString *fileName = [options objectForKey:@"fileName"];
    if (!fileName) {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyyMMdd_HHmmss"];
        fileName = [NSString stringWithFormat:@"audio_%@.m4a", [formatter stringFromDate:[NSDate date]]];
    }
    
    // Ensure we don't have duplicate extensions
    NSString *baseFileName = fileName;
    if ([fileName.pathExtension.lowercaseString isEqualToString:@"m4a"]) {
        baseFileName = [fileName stringByDeletingPathExtension];
    } else if ([fileName.pathExtension.lowercaseString isEqualToString:@"wav"]) {
        baseFileName = [fileName stringByDeletingPathExtension];
    }
    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    self.recordingFilePath = [documentsDirectory stringByAppendingPathComponent:fileName];
    
    NSLog(@"Documents directory: %@", documentsDirectory);
    NSLog(@"Recording file path: %@", self.recordingFilePath);
    
    // Ensure the documents directory exists
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:documentsDirectory]) {
        NSError *createDirError = nil;
        [fileManager createDirectoryAtPath:documentsDirectory 
               withIntermediateDirectories:YES 
                                attributes:nil 
                                     error:&createDirError];
        if (createDirError) {
            NSLog(@"Failed to create documents directory: %@", createDirError.localizedDescription);
            [self sendErrorResult:command withMessage:[NSString stringWithFormat:@"Failed to create documents directory: %@", createDirError.localizedDescription]];
            return;
        }
    }
    
    // Configure recording settings - Use AAC format (iOS preferred)
    NSNumber *sampleRate = [options objectForKey:@"sampleRate"] ?: @44100;
    NSNumber *channels = [options objectForKey:@"channels"] ?: @1;
    NSNumber *quality = [options objectForKey:@"quality"] ?: @1;
    NSString *format = [options objectForKey:@"format"] ?: @"m4a";
    
    NSLog(@"Sample rate: %@, Channels: %@, Quality: %@, Format: %@", sampleRate, channels, quality, format);
    
    // iOS prefers AAC format - much more reliable than WAV
    NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];
    
    // Determine format based on user preference
    if ([format.lowercaseString isEqualToString:@"wav"]) {
        // WAV format settings
        [settings setObject:@(1819304813) forKey:@"AVFormatIDKey"]; // kAudioFormatLinearPCM
        [settings setObject:sampleRate forKey:@"AVSampleRateKey"];
        [settings setObject:channels forKey:@"AVNumberOfChannelsKey"];
        [settings setObject:@(16) forKey:@"AVLinearPCMBitDepthKey"]; // 16-bit
        [settings setObject:@(NO) forKey:@"AVLinearPCMIsFloatKey"]; // Integer
        [settings setObject:@(NO) forKey:@"AVLinearPCMIsBigEndianKey"]; // Little endian
    } else {
        // Default to AAC format (recommended for iOS)
        [settings setObject:@(1633772320) forKey:@"AVFormatIDKey"]; // kAudioFormatMPEG4AAC
        [settings setObject:sampleRate forKey:@"AVSampleRateKey"];
        [settings setObject:channels forKey:@"AVNumberOfChannelsKey"];
    }
    
    // Set bit rate based on quality
    NSInteger bitRate = 128000; // Default 128 kbps
    if ([quality integerValue] == 0) { // LOW
        bitRate = 64000; // 64 kbps
    } else if ([quality integerValue] == 2) { // HIGH
        bitRate = 256000; // 256 kbps
    }
    [settings setObject:@(bitRate) forKey:@"AVEncoderBitRateKey"];
    
    // Set audio quality
    [settings setObject:@(0) forKey:@"AVEncoderAudioQualityKey"]; // High quality
    
    // Update file extension based on format
    if ([format.lowercaseString isEqualToString:@"wav"]) {
        fileName = [baseFileName stringByAppendingString:@".wav"];
        NSLog(@"Using WAV format with file: %@", fileName);
    } else {
        fileName = [baseFileName stringByAppendingString:@".m4a"];
        NSLog(@"Using AAC format with file: %@", fileName);
    }
    self.recordingFilePath = [documentsDirectory stringByAppendingPathComponent:fileName];
    
    NSLog(@"Audio settings: %@", settings);
    
    // Check microphone permission before creating recorder
    [self checkMicrophonePermission:^(BOOL granted) {
        if (!granted) {
            NSLog(@"❌ Microphone permission not granted");
            [self sendErrorResult:command withMessage:@"Microphone permission not granted"];
            return;
        }
        
        NSLog(@"✅ Microphone permission granted, proceeding with recorder creation");
        [self createAudioRecorderWithSettings:settings command:command];
    }];
}

- (void)createAudioRecorderWithSettings:(NSDictionary *)settings command:(CDVInvokedUrlCommand*)command {
    // Get the base filename and format for fallback attempts
    NSString *fileName = [command.arguments[0] objectForKey:@"fileName"];
    NSString *format = [command.arguments[0] objectForKey:@"format"] ?: @"m4a";
    
    if (!fileName) {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyyMMdd_HHmmss"];
        fileName = [NSString stringWithFormat:@"audio_%@", [formatter stringFromDate:[NSDate date]]];
    }
    
    NSString *baseFileName = fileName;
    if ([fileName.pathExtension.lowercaseString isEqualToString:@"m4a"]) {
        baseFileName = [fileName stringByDeletingPathExtension];
    } else if ([fileName.pathExtension.lowercaseString isEqualToString:@"wav"]) {
        baseFileName = [fileName stringByDeletingPathExtension];
    }
    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    
    // Create and start audio recorder using direct AVAudioRecorder approach
    NSLog(@"Creating audio recorder with direct AVAudioRecorder approach...");
    
    NSLog(@"Creating audio recorder with file path: %@", self.recordingFilePath);
    NSLog(@"Audio settings: %@", settings);
    
    // Create audio recorder using direct AVAudioRecorder approach
    id recorder = nil;
    NSError *error = nil;
    
    // Create the file URL
    NSURL *fileURL = [NSURL fileURLWithPath:self.recordingFilePath];
    NSLog(@"File URL: %@", fileURL);
    
    // Try to create AVAudioRecorder directly
    @try {
        // Create the recorder using the standard initializer
        recorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:&error];
        
        if (recorder) {
            NSLog(@"✅ AVAudioRecorder created successfully: %@", recorder);
        } else {
            NSLog(@"❌ AVAudioRecorder creation failed");
            if (error) {
                NSLog(@"❌ Error: %@", error.localizedDescription);
            }
        }
    } @catch (NSException *exception) {
        NSLog(@"❌ Exception during AVAudioRecorder creation: %@", exception.reason);
        recorder = nil;
    }
    
    // If the direct approach failed, try with minimal settings
    if (!recorder) {
        NSLog(@"Direct approach failed, trying with minimal settings...");
        
        // Try with minimal settings based on format
        NSMutableDictionary *minimalSettings = [[NSMutableDictionary alloc] init];
        
        if ([format.lowercaseString isEqualToString:@"wav"]) {
            // Minimal WAV settings
            [minimalSettings setObject:@(1819304813) forKey:@"AVFormatIDKey"]; // kAudioFormatLinearPCM
            [minimalSettings setObject:@(22050) forKey:@"AVSampleRateKey"]; // Lower sample rate
            [minimalSettings setObject:@(1) forKey:@"AVNumberOfChannelsKey"];
            [minimalSettings setObject:@(16) forKey:@"AVLinearPCMBitDepthKey"];
            [minimalSettings setObject:@(NO) forKey:@"AVLinearPCMIsFloatKey"];
            [minimalSettings setObject:@(NO) forKey:@"AVLinearPCMIsBigEndianKey"];
            
            NSString *minimalFileName = [baseFileName stringByAppendingString:@"_minimal.wav"];
            self.recordingFilePath = [documentsDirectory stringByAppendingPathComponent:minimalFileName];
            NSLog(@"Trying minimal WAV settings with file path: %@", self.recordingFilePath);
        } else {
            // Minimal AAC settings
            [minimalSettings setObject:@(1633772320) forKey:@"AVFormatIDKey"]; // kAudioFormatMPEG4AAC
            [minimalSettings setObject:@(22050) forKey:@"AVSampleRateKey"]; // Lower sample rate
            [minimalSettings setObject:@(1) forKey:@"AVNumberOfChannelsKey"];
            [minimalSettings setObject:@(64000) forKey:@"AVEncoderBitRateKey"]; // 64 kbps
            [minimalSettings setObject:@(0) forKey:@"AVEncoderAudioQualityKey"]; // High quality
            
            NSString *minimalFileName = [baseFileName stringByAppendingString:@"_minimal.m4a"];
            self.recordingFilePath = [documentsDirectory stringByAppendingPathComponent:minimalFileName];
            NSLog(@"Trying minimal AAC settings with file path: %@", self.recordingFilePath);
        }
        
        NSLog(@"Minimal settings: %@", minimalSettings);
        
        // Try again with minimal settings
        NSURL *minimalFileURL = [NSURL fileURLWithPath:self.recordingFilePath];
        error = nil;
        
        @try {
            recorder = [[AVAudioRecorder alloc] initWithURL:minimalFileURL settings:minimalSettings error:&error];
            
            if (recorder) {
                NSLog(@"✅ Minimal AVAudioRecorder created successfully: %@", recorder);
            } else {
                NSLog(@"❌ Minimal AVAudioRecorder creation failed");
                if (error) {
                    NSLog(@"❌ Minimal Error: %@", error.localizedDescription);
                }
            }
        } @catch (NSException *exception) {
            NSLog(@"❌ Exception during minimal AVAudioRecorder creation: %@", exception.reason);
            recorder = nil;
        }
    }
    
    // Final fallback - try with just basic settings
    if (!recorder) {
        NSLog(@"All attempts failed, trying with basic settings...");
        
        // Try with just the most basic settings possible
        NSMutableDictionary *basicSettings = [[NSMutableDictionary alloc] init];
        
        if ([format.lowercaseString isEqualToString:@"wav"]) {
            // Basic WAV settings
            [basicSettings setObject:@(1819304813) forKey:@"AVFormatIDKey"]; // kAudioFormatLinearPCM
            [basicSettings setObject:@(22050) forKey:@"AVSampleRateKey"]; // Lower sample rate
            [basicSettings setObject:@(1) forKey:@"AVNumberOfChannelsKey"];
            [basicSettings setObject:@(16) forKey:@"AVLinearPCMBitDepthKey"];
            [basicSettings setObject:@(NO) forKey:@"AVLinearPCMIsFloatKey"];
            [basicSettings setObject:@(NO) forKey:@"AVLinearPCMIsBigEndianKey"];
            
            NSString *basicFileName = [baseFileName stringByAppendingString:@"_basic.wav"];
            self.recordingFilePath = [documentsDirectory stringByAppendingPathComponent:basicFileName];
            NSLog(@"Trying basic WAV settings with file path: %@", self.recordingFilePath);
        } else {
            // Basic AAC settings
            [basicSettings setObject:@(1633772320) forKey:@"AVFormatIDKey"]; // kAudioFormatMPEG4AAC
            [basicSettings setObject:@(22050) forKey:@"AVSampleRateKey"]; // Lower sample rate
            [basicSettings setObject:@(1) forKey:@"AVNumberOfChannelsKey"];
            
            NSString *basicFileName = [baseFileName stringByAppendingString:@"_basic.m4a"];
            self.recordingFilePath = [documentsDirectory stringByAppendingPathComponent:basicFileName];
            NSLog(@"Trying basic AAC settings with file path: %@", self.recordingFilePath);
        }
        
        NSLog(@"Basic settings: %@", basicSettings);
        
        // Try again with basic settings
        NSURL *basicFileURL = [NSURL fileURLWithPath:self.recordingFilePath];
        error = nil;
        
        @try {
            recorder = [[AVAudioRecorder alloc] initWithURL:basicFileURL settings:basicSettings error:&error];
            
            if (recorder) {
                NSLog(@"✅ Basic AVAudioRecorder created successfully: %@", recorder);
            } else {
                NSLog(@"❌ Basic AVAudioRecorder creation failed");
                if (error) {
                    NSLog(@"❌ Basic Error: %@", error.localizedDescription);
                }
            }
        } @catch (NSException *exception) {
            NSLog(@"❌ Exception during basic AVAudioRecorder creation: %@", exception.reason);
            recorder = nil;
        }
    }
    
    if (!recorder) {
        NSLog(@"Audio recorder creation failed - returned nil");
        
        NSLog(@"❌ Failed to create audio recorder - all formats failed");
        NSLog(@"❌ Documents directory: %@", documentsDirectory);
        NSLog(@"❌ Recording file path: %@", self.recordingFilePath);
        
        // Check if the issue might be permissions
        [self checkMicrophonePermission:^(BOOL granted) {
            if (!granted) {
                NSLog(@"❌ Microphone permission not granted - this could be the issue");
            } else {
                NSLog(@"✅ Microphone permission is granted");
            }
        }];
        
        [self sendErrorResult:command withMessage:@"Failed to create audio recorder - all formats failed. Check console for detailed debug information."];
        return;
    }
    
    NSLog(@"Audio recorder created successfully: %@", recorder);
    self.audioRecorder = recorder;
    
    // Set delegate
    self.audioRecorder.delegate = self;
    
    self.recordingStartTime = [NSDate date];
    
    // Start recording
    BOOL success = [self.audioRecorder record];
    if (success) {
        self.isRecording = YES;
        self.isPaused = NO;
        
        NSDictionary *resultDict = @{
            @"message": @"Recording started successfully",
            @"filePath": self.recordingFilePath,
            @"startTime": @([self.recordingStartTime timeIntervalSince1970])
        };
        
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK 
                                                    messageAsDictionary:resultDict];
        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
    } else {
        [self sendErrorResult:command withMessage:@"Failed to start recording"];
    }
}

- (void)stopRecordingInternal:(CDVInvokedUrlCommand*)command {
    // Ensure we're on the main thread for all operations
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self stopRecordingInternal:command];
        });
        return;
    }
    
    if (![self.audioRecorder respondsToSelector:@selector(stop)]) {
        [self sendErrorResult:command withMessage:@"Stop method not available"];
        return;
    }
    
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [self.audioRecorder performSelector:@selector(stop)];
    #pragma clang diagnostic pop
    
    NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:self.recordingStartTime];
    
    // Get file size
    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self.recordingFilePath error:nil];
    NSNumber *fileSize = [fileAttributes objectForKey:NSFileSize];
    
    self.isRecording = NO;
    self.isPaused = NO;
    
    // Convert to blob
    [self convertFileToBlob:command withDuration:duration fileSize:fileSize];
}

- (void)convertFileToBlob:(CDVInvokedUrlCommand*)command {
    [self convertFileToBlob:command withDuration:0 fileSize:nil];
}

- (void)convertFileToBlob:(CDVInvokedUrlCommand*)command withDuration:(NSTimeInterval)duration fileSize:(NSNumber*)fileSize {
    if (!self.recordingFilePath || ![[NSFileManager defaultManager] fileExistsAtPath:self.recordingFilePath]) {
        [self sendErrorResult:command withMessage:@"No recorded file found"];
        return;
    }
    
    NSData *audioData = [NSData dataWithContentsOfFile:self.recordingFilePath];
    if (!audioData) {
        [self sendErrorResult:command withMessage:@"Failed to read audio file"];
        return;
    }
    
    NSString *base64Audio = [audioData base64EncodedStringWithOptions:0];
    
    // Determine MIME type and format based on file extension
    NSString *mimeType = @"audio/mp4"; // Default for M4A
    NSString *format = @"m4a";
    
    if ([self.recordingFilePath.pathExtension.lowercaseString isEqualToString:@"wav"]) {
        mimeType = @"audio/wav";
        format = @"wav";
    } else if ([self.recordingFilePath.pathExtension.lowercaseString isEqualToString:@"m4a"]) {
        mimeType = @"audio/mp4";
        format = @"m4a";
    } else if ([self.recordingFilePath.pathExtension.lowercaseString isEqualToString:@"caf"]) {
        mimeType = @"audio/x-caf";
        format = @"caf";
    }
    
    NSString *blobUrl = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, base64Audio];
    
    if (!fileSize) {
        fileSize = @(audioData.length);
    }
    
    if (duration == 0) {
        duration = [[NSDate date] timeIntervalSinceDate:self.recordingStartTime];
    }
    
    NSDictionary *resultDict = @{
        @"audioData": base64Audio,
        @"audioBlob": blobUrl,
        @"filePath": self.recordingFilePath,
        @"duration": @(duration),
        @"fileSize": fileSize,
        @"format": format,
        @"mimeType": mimeType
    };
    
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK 
                                                messageAsDictionary:resultDict];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

#pragma mark - Interval Recording

- (void)recordWithInterval:(CDVInvokedUrlCommand*)command {
    // Check if already recording
    if (self.isRecording) {
        [self sendErrorResult:command withMessage:@"Already recording. Stop current recording first."];
        return;
    }
    
    // Get interval duration from arguments
    NSDictionary *options = [command.arguments objectAtIndex:0];
    NSNumber *durationSeconds = [options objectForKey:@"duration"];
    
    if (!durationSeconds || [durationSeconds doubleValue] <= 0) {
        [self sendErrorResult:command withMessage:@"Invalid duration. Must be greater than 0 seconds."];
        return;
    }
    
    // Store the command for later use
    self.currentCommand = command;
    
    // Start recording with the provided options
    [self startRecordingInternal:command];
    
    // Schedule automatic stop after the specified duration
    dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)([durationSeconds doubleValue] * NSEC_PER_SEC));
    dispatch_after(delay, dispatch_get_main_queue(), ^{
        if (self.isRecording) {
            [self stopRecordingInternal:self.currentCommand];
        }
    });
}

@end 