#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#import <CoreVideo/CoreVideo.h>
#import <QuartzCore/QuartzCore.h>
#import <AppKit/AppKit.h>
#include <string>
#import "logging.h"
#import "sync_timeline.h"
#import "recording_writer_safety.h"
#include <atomic>

// Import audio recorder
extern "C" void* createNativeAudioRecorder(void);
extern "C" bool startNativeAudioRecording(void* recorder, const char* deviceId, const char* outputPath);
extern "C" bool stopNativeAudioRecording(void* recorder);
extern "C" void destroyNativeAudioRecorder(void* recorder);

static AVAssetWriter *g_avWriter = nil;
static AVAssetWriterInput *g_avVideoInput = nil;
static AVAssetWriterInputPixelBufferAdaptor *g_avPixelBufferAdaptor = nil;
static dispatch_source_t g_avTimer = nil;
static dispatch_queue_t g_avCaptureQueue = nil;
static std::atomic<bool> g_avIsStopping(false);
static CGDirectDisplayID g_avDisplayID = 0;
static CGRect g_avCaptureRect = CGRectZero;
static std::atomic<bool> g_avIsRecording(false);
static int64_t g_avFrameNumber = 0;
static CMTime g_avStartTime;
static void* g_avAudioRecorder = nil;
static NSString* g_avAudioOutputPath = nil;
static const NSInteger kAVFoundationHighQualityVideoBitrate = 100 * 1000 * 1000;

// AVFoundation screen recording implementation
extern "C" bool startAVFoundationRecording(const std::string& outputPath,
                                           CGDirectDisplayID displayID,
                                           uint32_t windowID,
                                           CGRect captureRect,
                                           bool captureCursor,
                                           bool includeMicrophone,
                                           bool includeSystemAudio,
                                           NSString* audioDeviceId,
                                           NSString* audioOutputPath,
                                           double requestedFrameRate,
                                           NSString* qualityPreset) {
    
    if (g_avIsRecording) {
        NSLog(@"❌ AVFoundation recording already in progress");
        return false;
    }

    @try {
        MRLog(@"🎬 AVFoundation: Starting recording initialization");

        // Create output URL
        NSString *outputPathStr = [NSString stringWithUTF8String:outputPath.c_str()];
        NSURL *outputURL = [NSURL fileURLWithPath:outputPathStr];
        
        // Remove existing file
        NSError *removeError = nil;
        [[NSFileManager defaultManager] removeItemAtURL:outputURL error:&removeError];
        if (removeError && removeError.code != NSFileNoSuchFileError) {
            MRLog(@"⚠️ AVFoundation: Warning removing existing file: %@", removeError);
        }
        
        // Create asset writer
        NSError *error = nil;
        g_avWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error];
        if (!g_avWriter || error) {
            NSLog(@"❌ AVFoundation: Failed to create AVAssetWriter: %@", error);
            return false;
        }
        
        // Get display dimensions with proper scaling for macOS 14/13 compatibility
        CGRect displayBounds = CGDisplayBounds(displayID);
        
        // Get both logical (bounds) and physical (pixels) dimensions
        CGSize logicalSize = displayBounds.size;
        CGSize physicalSize = CGSizeMake(CGDisplayPixelsWide(displayID), CGDisplayPixelsHigh(displayID));
        
        // Calculate scale factor
        CGFloat scaleX = physicalSize.width / logicalSize.width;
        CGFloat scaleY = physicalSize.height / logicalSize.height;
        CGFloat scaleFactor = MAX(scaleX, scaleY); // Use max to handle non-uniform scaling
        
        // CRITICAL FIX: Use actual captured image dimensions for pixel buffer
        // CGDisplayCreateImage returns physical pixels on Retina displays
        CGImageRef testImage = CGDisplayCreateImage(displayID);
        if (!testImage) {
            NSLog(@"❌ AVFoundation: Failed to create display image for displayID %u", displayID);
            NSLog(@"   Display may be invalid. Retrying with main display...");
            displayID = CGMainDisplayID();
            testImage = CGDisplayCreateImage(displayID);
            if (!testImage) {
                NSLog(@"❌ AVFoundation: Failed to create image even for main display");
                return false;
            }
        }
        CGSize actualImageSize = CGSizeMake(CGImageGetWidth(testImage), CGImageGetHeight(testImage));
        CGImageRelease(testImage);
        
        // CRITICAL FIX: Use actual image dimensions to match what CGDisplayCreateImage returns
        // This prevents the "1/4 recording area" bug on Retina displays
        CGSize recordingSize;
        if (!CGRectIsEmpty(captureRect)) {
            // Scale capture rect to match actual image dimensions
            recordingSize = CGSizeMake(
                captureRect.size.width * (actualImageSize.width / logicalSize.width),
                captureRect.size.height * (actualImageSize.height / logicalSize.height)
            );
        } else {
            // Full screen: use actual image size
            recordingSize = actualImageSize;
        }
        
        MRLog(@"🎯 CRITICAL: Logical %.0fx%.0f → Actual image %.0fx%.0f", 
              logicalSize.width, logicalSize.height, actualImageSize.width, actualImageSize.height);
        
        MRLog(@"🖥️ Display bounds (logical): %.0fx%.0f", logicalSize.width, logicalSize.height);
        MRLog(@"🖥️ Display pixels (physical): %.0fx%.0f", physicalSize.width, physicalSize.height);
        
        if (scaleFactor > 1.5) {
            MRLog(@"🔍 Scale factor: %.1fx → Retina display detected (macOS 14/13 scaling fix applied)", scaleFactor);
        } else if (scaleFactor > 1.1) {
            MRLog(@"🔍 Scale factor: %.1fx → Non-standard scaling detected", scaleFactor);
        } else {
            MRLog(@"🔍 Scale factor: %.1fx → Standard display", scaleFactor);
        }
        
        // H.264 4:2:0 CIFT boyut ister — bkz. screen_capture_kit.mm'deki ayni guard.
        recordingSize.width = MAX(2.0, floor(recordingSize.width / 2.0) * 2.0);
        recordingSize.height = MAX(2.0, floor(recordingSize.height / 2.0) * 2.0);

        MRLog(@"🎯 Recording size: %.0fx%.0f (using actual physical dimensions for Retina fix)", recordingSize.width, recordingSize.height);
        
        NSString *normalizedQuality = @"high";
        if ([qualityPreset isKindOfClass:[NSString class]] && qualityPreset.length > 0) {
            normalizedQuality = [qualityPreset lowercaseString];
            if (![normalizedQuality isEqualToString:@"low"] &&
                ![normalizedQuality isEqualToString:@"medium"] &&
                ![normalizedQuality isEqualToString:@"high"]) {
                normalizedQuality = @"high";
            }
        }
        double fps = requestedFrameRate > 0 ? requestedFrameRate : 60.0;
        if (fps < 1.0) fps = 1.0;
        if (fps > 120.0) fps = 120.0;

        NSString *codecKey = AVVideoCodecTypeH264;
        NSInteger bitrate = kAVFoundationHighQualityVideoBitrate;

        if ([normalizedQuality isEqualToString:@"low"]) {
            NSInteger multiplier = 10;
            NSInteger minBitrate = 10 * 1000 * 1000;
            NSInteger maxBitrate = 45 * 1000 * 1000;
            bitrate = (NSInteger)(recordingSize.width * recordingSize.height * multiplier);
            bitrate = MAX(bitrate, minBitrate);
            bitrate = MIN(bitrate, maxBitrate);
        } else if ([normalizedQuality isEqualToString:@"medium"]) {
            NSInteger multiplier = 18;
            NSInteger minBitrate = 18 * 1000 * 1000;
            NSInteger maxBitrate = 80 * 1000 * 1000;
            bitrate = (NSInteger)(recordingSize.width * recordingSize.height * multiplier);
            bitrate = MAX(bitrate, minBitrate);
            bitrate = MIN(bitrate, maxBitrate);
        } else { // high - çözünürlüğe DUYARLI yüksek kalite (eski sabit 50 Mbps yerine)
            NSInteger multiplier = 32; // ~0.53 bpp @60fps
            NSInteger minBitrate = kAVFoundationHighQualityVideoBitrate; // 100 Mbps taban
            NSInteger maxBitrate = 200 * 1000 * 1000;                    // 200 Mbps tavan
            bitrate = (NSInteger)(recordingSize.width * recordingSize.height * multiplier);
            bitrate = MAX(bitrate, minBitrate);
            bitrate = MIN(bitrate, maxBitrate);
        }

        MRLog(@"🎬 AVFoundation encoder (%@): %dx%d, codec=H.264 High Profile, bitrate=%.2fMbps",
              normalizedQuality,
              (int)recordingSize.width,
              (int)recordingSize.height,
              bitrate / (1000.0 * 1000.0));

        NSDictionary *videoSettings = @{
            AVVideoCodecKey: codecKey,
            AVVideoWidthKey: @((int)recordingSize.width),
            AVVideoHeightKey: @((int)recordingSize.height),
            AVVideoCompressionPropertiesKey: @{
                AVVideoAverageBitRateKey: @(bitrate),
                AVVideoMaxKeyFrameIntervalKey: @((int)fps),
                AVVideoAllowFrameReorderingKey: @YES,
                AVVideoExpectedSourceFrameRateKey: @((int)fps),
                // AVVideoQualityKey BILEREK YOK — bkz. screen_capture_kit.mm:
                // avc1 icin gecersiz, yazilim encoder yolunda AVAssetWriterInput
                // istisna atip kaydi sessizce bos birakiyor.
                AVVideoProfileLevelKey: AVVideoProfileLevelH264HighAutoLevel,
                AVVideoH264EntropyModeKey: AVVideoH264EntropyModeCABAC
            }
        };
        
        // Create video input — kademeli geri dusus (bkz. screen_capture_kit.mm).
        // AVFoundation reddettigi sikistirma ozelliginde NSError degil ISTISNA
        // atiyor; yakalanmazsa kayit sessizce bos cikiyor.
        NSArray<NSDictionary *> *settingsTiers = @[
            videoSettings,
            @{
                AVVideoCodecKey: codecKey,
                AVVideoWidthKey: @((int)recordingSize.width),
                AVVideoHeightKey: @((int)recordingSize.height),
                AVVideoCompressionPropertiesKey: @{
                    AVVideoAverageBitRateKey: @(bitrate),
                    AVVideoMaxKeyFrameIntervalKey: @((int)fps),
                    AVVideoProfileLevelKey: AVVideoProfileLevelH264HighAutoLevel
                }
            },
            @{
                AVVideoCodecKey: codecKey,
                AVVideoWidthKey: @((int)recordingSize.width),
                AVVideoHeightKey: @((int)recordingSize.height),
                AVVideoCompressionPropertiesKey: @{ AVVideoAverageBitRateKey: @(bitrate) }
            },
            @{
                AVVideoCodecKey: codecKey,
                AVVideoWidthKey: @((int)recordingSize.width),
                AVVideoHeightKey: @((int)recordingSize.height)
            }
        ];
        g_avVideoInput = nil;
        NSString *lastRejection = nil;
        for (NSUInteger tier = 0; tier < settingsTiers.count; tier++) {
            @try {
                g_avVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                                                   outputSettings:settingsTiers[tier]];
            } @catch (NSException *exception) {
                g_avVideoInput = nil;
                lastRejection = exception.reason;
                NSLog(@"⚠️ AVFoundation encoder settings tier %lu rejected: %@", (unsigned long)tier, exception.reason);
                continue;
            }
            if (g_avVideoInput) {
                if (tier > 0) {
                    NSLog(@"⚠️ AVFoundation encoder fell back to settings tier %lu; last rejection: %@",
                          (unsigned long)tier, lastRejection);
                }
                break;
            }
        }
        if (!g_avVideoInput) {
            NSLog(@"❌ AVFoundation: no accepted H.264 encoder settings (%@)", lastRejection ?: @"unknown");
            return false;
        }
        g_avVideoInput.expectsMediaDataInRealTime = YES;
        
        // Create pixel buffer adaptor with compatibility
        OSType pixelFormat;
        if (@available(macOS 13.0, *)) {
            pixelFormat = kCVPixelFormatType_32ARGB;  // Modern format
        } else {
            pixelFormat = kCVPixelFormatType_32BGRA;  // Legacy compatibility
        }
        
        NSDictionary *pixelBufferAttributes = @{
            (NSString*)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat),
            (NSString*)kCVPixelBufferWidthKey: @((int)recordingSize.width),
            (NSString*)kCVPixelBufferHeightKey: @((int)recordingSize.height),
            (NSString*)kCVPixelBufferCGImageCompatibilityKey: @YES,
            (NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey: @YES
        };
        
        MRLog(@"🔧 Using pixel format: %u", pixelFormat);
        
        g_avPixelBufferAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:g_avVideoInput sourcePixelBufferAttributes:pixelBufferAttributes];
        
        // Add input to writer
        if (![g_avWriter canAddInput:g_avVideoInput]) {
            NSLog(@"❌ Cannot add video input to AVAssetWriter");
            return false;
        }
        [g_avWriter addInput:g_avVideoInput];
        
        // Start writing
        if (![g_avWriter startWriting]) {
            NSLog(@"❌ Failed to start AVAssetWriter: %@", g_avWriter.error);
            return false;
        }
        
        g_avStartTime = kCMTimeInvalid;
        
        // Store recording parameters with scaling correction
        g_avDisplayID = displayID;
        
        // CRITICAL FIX: Scale capture coordinates to match physical pixels
        if (!CGRectIsEmpty(captureRect)) {
            // Scale coordinates from logical to physical (for CGDisplayCreateImage)
            CGFloat scaleFactorX = actualImageSize.width / logicalSize.width;
            CGFloat scaleFactorY = actualImageSize.height / logicalSize.height;
            
            g_avCaptureRect = CGRectMake(
                captureRect.origin.x * scaleFactorX,
                captureRect.origin.y * scaleFactorY,
                captureRect.size.width * scaleFactorX,
                captureRect.size.height * scaleFactorY
            );
            
            NSLog(@"🔲 RETINA FIX: Logical (%.0f,%.0f %.0fx%.0f) → Physical (%.0f,%.0f %.0fx%.0f)", 
                  captureRect.origin.x, captureRect.origin.y, captureRect.size.width, captureRect.size.height,
                  g_avCaptureRect.origin.x, g_avCaptureRect.origin.y, g_avCaptureRect.size.width, g_avCaptureRect.size.height);
            
            // Validate coordinates are within physical display bounds
            if (g_avCaptureRect.origin.x >= 0 && g_avCaptureRect.origin.y >= 0 && 
                g_avCaptureRect.origin.x + g_avCaptureRect.size.width <= actualImageSize.width &&
                g_avCaptureRect.origin.y + g_avCaptureRect.size.height <= actualImageSize.height) {
                NSLog(@"✅ Coordinates validated within physical display bounds %.0fx%.0f", actualImageSize.width, actualImageSize.height);
            } else {
                NSLog(@"⚠️ Coordinates may be outside physical display bounds - clipping may occur");
            }
        } else {
            g_avCaptureRect = CGRectZero; // Full screen
            NSLog(@"🖥️ Full screen capture using physical dimensions %.0fx%.0f", actualImageSize.width, actualImageSize.height);
        }
        
        g_avFrameNumber = 0;

        // Start audio recording if requested
        if (includeMicrophone || includeSystemAudio) {
            MRLog(@"🎤 Starting audio capture (mic=%d, system=%d)", includeMicrophone, includeSystemAudio);

            // Use provided audio output path or generate one
            NSString *audioPath = nil;
            if (audioOutputPath && [audioOutputPath length] > 0) {
                audioPath = audioOutputPath;
                MRLog(@"🎤 Using provided audio path: %@", audioPath);
            } else {
                NSString *videoDir = [outputPathStr stringByDeletingLastPathComponent];
                NSString *audioFilename = [NSString stringWithFormat:@"avf_audio_%ld.mov", (long)[[NSDate date] timeIntervalSince1970]];
                audioPath = [videoDir stringByAppendingPathComponent:audioFilename];
                MRLog(@"🎤 Generated audio path: %@", audioPath);
            }

            // Ensure .mov extension
            if (![audioPath.pathExtension.lowercaseString isEqualToString:@"mov"]) {
                audioPath = [[audioPath stringByDeletingPathExtension] stringByAppendingPathExtension:@"mov"];
                MRLog(@"🔧 Fixed audio extension to .mov: %@", audioPath);
            }

            // Copy to retain the string (ARC will manage it)
            g_avAudioOutputPath = [audioPath copy];

            // Create audio recorder
            g_avAudioRecorder = createNativeAudioRecorder();

            if (g_avAudioRecorder) {
                const char* deviceIdCStr = audioDeviceId ? [audioDeviceId UTF8String] : NULL;
                const char* outputPathCStr = [g_avAudioOutputPath UTF8String];

                if (startNativeAudioRecording(g_avAudioRecorder, deviceIdCStr, outputPathCStr)) {
                    MRLog(@"✅ Audio recording started to: %@", g_avAudioOutputPath);
                } else {
                    NSLog(@"❌ Failed to start audio recording");
                    destroyNativeAudioRecorder(g_avAudioRecorder);
                    g_avAudioRecorder = nil;
                    g_avAudioOutputPath = nil;
                }
            } else {
                NSLog(@"❌ Failed to create audio recorder");
            }
        }

        // Start capture timer using target FPS
        dispatch_queue_t captureQueue = dispatch_queue_create("AVFoundationCaptureQueue", DISPATCH_QUEUE_SERIAL);
        g_avCaptureQueue = captureQueue;
        g_avTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, captureQueue);
        
        if (!g_avTimer) {
            NSLog(@"❌ Failed to create dispatch timer");
            return false;
        }
        
        uint64_t interval = (uint64_t)(NSEC_PER_SEC / fps);
        dispatch_source_set_timer(g_avTimer, dispatch_time(DISPATCH_TIME_NOW, 0), interval, interval / 10);
        
        // Retain objects before passing to block to prevent deallocation
        AVAssetWriterInput *localVideoInput = g_avVideoInput;
        AVAssetWriterInputPixelBufferAdaptor *localPixelBufferAdaptor = g_avPixelBufferAdaptor;
        
        dispatch_source_set_event_handler(g_avTimer, ^{
            if (!g_avIsRecording) return;
            if (MRSyncIsPaused()) return;

            // Additional null checks for Electron safety
            if (!localVideoInput || !localPixelBufferAdaptor) {
                NSLog(@"⚠️ Video input or pixel buffer adaptor is nil, stopping recording");
                g_avIsRecording = false;
                return;
            }

            CMTime hostTimestamp = CMClockGetTime(CMClockGetHostTimeClock());
            if (MRSyncShouldHoldVideoFrame(hostTimestamp)) {
                return;
            }

            @autoreleasepool {
                @try {
                    // Capture screen with Electron-safe error handling
                    CGImageRef screenImage = nil;
                    if (CGRectIsEmpty(g_avCaptureRect)) {
                        screenImage = CGDisplayCreateImage(g_avDisplayID);
                    } else {
                        CGImageRef fullScreen = CGDisplayCreateImage(g_avDisplayID);
                        if (fullScreen) {
                            screenImage = CGImageCreateWithImageInRect(fullScreen, g_avCaptureRect);
                            CGImageRelease(fullScreen);
                        }
                    }
                    
                    if (!screenImage) {
                        NSLog(@"⚠️ Failed to capture screen image, skipping frame");
                        return;
                    }
                
                    // Convert to pixel buffer with Electron-safe error handling
                    CVPixelBufferRef pixelBuffer = nil;
                    CVReturn cvRet = CVPixelBufferPoolCreatePixelBuffer(NULL, localPixelBufferAdaptor.pixelBufferPool, &pixelBuffer);
                    
                    if (cvRet == kCVReturnSuccess && pixelBuffer) {
                        // Check pixel buffer dimensions match screen image
                        size_t bufferWidth = CVPixelBufferGetWidth(pixelBuffer);
                        size_t bufferHeight = CVPixelBufferGetHeight(pixelBuffer);
                        size_t imageWidth = CGImageGetWidth(screenImage);
                        size_t imageHeight = CGImageGetHeight(screenImage);
                        
                        MRLog(@"🔍 Debug: Buffer %zux%zu, Image %zux%zu", bufferWidth, bufferHeight, imageWidth, imageHeight);
                        
                        if (bufferWidth != imageWidth || bufferHeight != imageHeight) {
                            MRLog(@"🔧 EXPECTED SIZE DIFFERENCE: Buffer %zux%zu (logical) vs Image %zux%zu (physical)", bufferWidth, bufferHeight, imageWidth, imageHeight);
                            MRLog(@"   This is normal on Retina displays - scaling handled correctly now");
                        }
                        
                        CVPixelBufferLockBaseAddress(pixelBuffer, 0);
                        
                        void *pixelData = CVPixelBufferGetBaseAddress(pixelBuffer);
                        if (!pixelData) {
                            NSLog(@"⚠️ Failed to get pixel buffer base address");
                            CVPixelBufferRelease(pixelBuffer);
                            CGImageRelease(screenImage);
                            return;
                        }
                        
                        size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
                        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
                        if (!colorSpace) {
                            NSLog(@"⚠️ Failed to create color space");
                            CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
                            CVPixelBufferRelease(pixelBuffer);
                            CGImageRelease(screenImage);
                            return;
                        }
                        
                        // Match bitmap info to pixel format for compatibility
                        CGBitmapInfo bitmapInfo;
                        OSType currentPixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer);
                        if (currentPixelFormat == kCVPixelFormatType_32ARGB) {
                            bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big;
                        } else { // kCVPixelFormatType_32BGRA
                            bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little;
                        }
                        
                        CGContextRef context = CGBitmapContextCreate(pixelData, 
                                                                   CVPixelBufferGetWidth(pixelBuffer),
                                                                   CVPixelBufferGetHeight(pixelBuffer), 
                                                                   8, bytesPerRow, colorSpace, bitmapInfo);
                        
                        if (context) {
                            // CRITICAL FIX: Draw image at correct size - scale physical image to logical buffer size
                            CGSize bufferSize = CGSizeMake(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));
                            CGContextDrawImage(context, CGRectMake(0, 0, bufferSize.width, bufferSize.height), screenImage);
                            CGContextRelease(context);
                            
                            // Write frame only if input is ready
                            if (localVideoInput && localVideoInput.readyForMoreMediaData) {
                                CMTime currentTimestamp = CMClockGetTime(CMClockGetHostTimeClock());

                                if (CMTIME_IS_INVALID(g_avStartTime)) {
                                    // Join the shared t=0 used by camera/audio.
                                    g_avStartTime = MRSyncWriterStartTime(currentTimestamp);
                                    [g_avWriter startSessionAtSourceTime:kCMTimeZero];
                                    g_avFrameNumber = 0;
                                    MRLog(@"🎞️ AVFoundation writer session started (zero-based timeline)");
                                }

                                CMTime relativeTime = CMTimeSubtract(currentTimestamp, g_avStartTime);
                                if (!CMTIME_IS_VALID(relativeTime) || CMTIME_COMPARE_INLINE(relativeTime, <, kCMTimeZero)) {
                                    relativeTime = kCMTimeZero;
                                }
                                CMTime presentationTime = MRSyncAdjustForPauses(
                                    CMTimeMakeWithSeconds(CMTimeGetSeconds(relativeTime), 600));

                                double stopLimit = MRSyncGetStopLimitSeconds();
                                if (stopLimit > 0) {
                                    double secondsFromStart = CMTimeGetSeconds(presentationTime);
                                    double tolerance = fps > 0 ? (1.5 / fps) : 0.02;
                                    if (tolerance < 0.02) {
                                        tolerance = 0.02;
                                    }
                                    if (secondsFromStart > stopLimit + tolerance) {
                                        MRLog(@"⏹️ Screen frame skipped at %.3fs (limit %.3fs)", secondsFromStart, stopLimit);
                                        CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
                                        CVPixelBufferRelease(pixelBuffer);
                                        CGImageRelease(screenImage);
                                        return;
                                    }
                                }

                                if (g_avFrameNumber == 0 &&
                                    CMTimeCompare(presentationTime, kCMTimeZero) > 0) {
                                    // Late start vs shared t=0: hold first frame from 0.
                                    [localPixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:kCMTimeZero];
                                }
                                BOOL appendSuccess = [localPixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:presentationTime];
                                if (appendSuccess) {
                                    g_avFrameNumber++;
                                } else {
                                    NSLog(@"⚠️ Failed to append pixel buffer");
                                }
                            }
                        } else {
                            NSLog(@"⚠️ Failed to create bitmap context");
                        }
                        
                        CGColorSpaceRelease(colorSpace);
                        CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
                        CVPixelBufferRelease(pixelBuffer);
                    } else {
                        NSLog(@"⚠️ Failed to create pixel buffer: %d", cvRet);
                    }
                    
                    CGImageRelease(screenImage);
                } @catch (NSException *exception) {
                    NSLog(@"❌ Exception in AVFoundation capture loop: %@", exception.reason);
                    g_avIsRecording = false; // Stop recording on exception to prevent crash
                }
            }
        });
        
        dispatch_resume(g_avTimer);
        g_avIsRecording = true;
        
        MRLog(@"🎥 AVFoundation recording started: %dx%d @ %.0ffps", 
              (int)recordingSize.width, (int)recordingSize.height, fps);
        
        return true;
        
    } @catch (NSException *exception) {
        NSLog(@"❌ Exception in AVFoundation recording: %@", exception.reason);
        return false;
    }
}

extern "C" bool stopAVFoundationRecording() {
    if (g_avIsStopping.exchange(true)) return false;
    g_avIsRecording = false;
    BOOL finished = YES;
    @try {
        // Cancelling a timer does not wait for an in-flight frame. Drain its
        // serial queue before finishing or releasing the writer it uses.
        if (g_avTimer) dispatch_source_cancel(g_avTimer);
        if (g_avCaptureQueue) dispatch_sync(g_avCaptureQueue, ^{});
        if (g_avAudioRecorder) {
            @try {
                stopNativeAudioRecording(g_avAudioRecorder);
                destroyNativeAudioRecorder(g_avAudioRecorder);
            } @catch (NSException *exception) {
                NSLog(@"[Recorder] Fallback audio stop failed safely: %@", exception.reason);
            }
            g_avAudioRecorder = nil;
            [g_avAudioOutputPath release];
            g_avAudioOutputPath = nil;
        }
        finished = MRFinishAssetWriterSafely(g_avWriter, 5.0);
    } @catch (NSException *exception) {
        NSLog(@"[Recorder] Fallback stop failed safely: %@", exception.reason);
        finished = NO;
    } @finally {
        [g_avWriter release];
        g_avWriter = nil;
        g_avVideoInput = nil;
        g_avPixelBufferAdaptor = nil;
        if (g_avTimer) dispatch_release(g_avTimer);
        g_avTimer = nil;
        if (g_avCaptureQueue) dispatch_release(g_avCaptureQueue);
        g_avCaptureQueue = nil;
        g_avFrameNumber = 0;
        g_avStartTime = kCMTimeInvalid;
        g_avIsStopping = false;
    }
    return finished;
}

extern "C" bool hasAVFoundationRecordingResources() {
    return g_avIsRecording || g_avIsStopping || g_avWriter != nil || g_avTimer != nil || g_avAudioRecorder != nil;
}

extern "C" bool isAVFoundationRecordingStopping() {
    return g_avIsStopping;
}

extern "C" bool isAVFoundationRecording() {
    return g_avIsRecording;
}

extern "C" NSString* getAVFoundationAudioPath() {
    return g_avAudioOutputPath;
}
