#import "avfoundation_control.h"

#ifdef __APPLE__

#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#include <iostream>
#include <string>

AVFoundationControl::AVFoundationControl() 
    : m_device(nullptr), m_session(nullptr), m_input(nullptr), m_initialized(false) {
}

AVFoundationControl::~AVFoundationControl() {
    releaseDevice();
}

bool AVFoundationControl::setupCaptureSession() {
    @autoreleasepool {
        m_session = [[AVCaptureSession alloc] init];
        if (!m_session) return false;
        
        [m_session beginConfiguration];
        
        // Set session preset for high quality
        if ([m_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
            [m_session setSessionPreset:AVCaptureSessionPreset1280x720];
        }
        
        // Create device input
        NSError* error = nil;
        m_input = [[AVCaptureDeviceInput alloc] initWithDevice:(AVCaptureDevice*)m_device error:&error];
        if (!m_input || error) {
            [m_session commitConfiguration];
            return false;
        }
        
        // Add input to session
        if ([m_session canAddInput:m_input]) {
            [m_session addInput:m_input];
        } else {
            [m_session commitConfiguration];
            return false;
        }
        
        [m_session commitConfiguration];
        return true;
    }
}

void AVFoundationControl::cleanupCaptureSession() {
    @autoreleasepool {
        if (m_session) {
            [m_session stopRunning];
            if (m_input) {
                [m_session removeInput:m_input];
                m_input = nil;
            }
            m_session = nil;
        }
        
        if (m_device) {
            if ([m_device isLockingCameraConfigurationWithMinimumFrameDuration]) {
                [m_device unlockForConfiguration];
            }
            m_device = nil;
        }
    }
}

AVCaptureDevice* AVFoundationControl::findLogitechBrioDevice() {
    @autoreleasepool {
        // Get available video devices
        AVCaptureDeviceDiscoverySession* discoverySession = [AVCaptureDeviceDiscoverySession
            discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeExternalUnknown]
                                  mediaType:AVMediaTypeVideo
                                   position:AVCaptureDevicePositionUnspecified];
        
        NSArray<AVCaptureDevice*>* devices = [discoverySession devices];
        
        for (AVCaptureDevice* device in devices) {
            NSString* deviceName = [device localizedName];
            NSString* modelID = [device modelID];
            
            // Check if this is a Logitech BRIO device
            if ([deviceName containsString:@"BRIO"] || 
                [deviceName containsString:@"MX Brio"] ||
                [deviceName containsString:@"Logitech"]) {
                return device;
            }
        }
        
        return nil;
    }
}

std::vector<CameraDevice> AVFoundationControl::discoverDevices() {
    std::vector<CameraDevice> devices;
    
    @autoreleasepool {
        AVCaptureDeviceDiscoverySession* discoverySession = [AVCaptureDeviceDiscoverySession
            discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeExternalUnknown]
                                  mediaType:AVMediaTypeVideo
                                   position:AVCaptureDevicePositionUnspecified];
        
        NSArray<AVCaptureDevice*>* avDevices = [discoverySession devices];
        
        for (AVCaptureDevice* device in avDevices) {
            NSString* deviceName = [device localizedName];
            
            // Check if this is a Logitech device
            if ([deviceName containsString:@"Logitech"] ||
                [deviceName containsString:@"BRIO"] ||
                [deviceName containsString:@"MX Brio"]) {
                
                CameraDevice cameraDevice;
                cameraDevice.name = std::string([deviceName UTF8String]);
                cameraDevice.id = std::string([[device uniqueID] UTF8String]);
                cameraDevice.vendorId = 0x046d; // Logitech vendor ID
                
                // Determine product ID based on device name
                if ([deviceName containsString:@"MX Brio"]) {
                    cameraDevice.productId = 0x085e;
                } else if ([deviceName containsString:@"BRIO"]) {
                    cameraDevice.productId = 0x085b;
                }
                
                devices.push_back(cameraDevice);
            }
        }
    }
    
    return devices;
}

bool AVFoundationControl::initializeDevice(const std::string& deviceId) {
    if (m_initialized) {
        releaseDevice();
    }
    
    @autoreleasepool {
        // Find device by unique ID
        NSString* targetDeviceId = [NSString stringWithUTF8String:deviceId.c_str()];
        
        AVCaptureDeviceDiscoverySession* discoverySession = [AVCaptureDeviceDiscoverySession
            discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeExternalUnknown]
                                  mediaType:AVMediaTypeVideo
                                   position:AVCaptureDevicePositionUnspecified];
        
        NSArray<AVCaptureDevice*>* avDevices = [discoverySession devices];
        
        for (AVCaptureDevice* device in avDevices) {
            if ([[device uniqueID] isEqualToString:targetDeviceId]) {
                m_device = device;
                break;
            }
        }
        
        if (!m_device) {
            // Fallback: find any Logitech BRIO device
            m_device = findLogitechBrioDevice();
        }
        
        if (!m_device) return false;
        
        // Lock device for configuration
        NSError* error = nil;
        if (![m_device lockForConfiguration:&error]) {
            return false;
        }
        
        if (!setupCaptureSession()) {
            [m_device unlockForConfiguration];
            return false;
        }
        
        m_initialized = true;
        return true;
    }
}

void AVFoundationControl::releaseDevice() {
    if (m_initialized) {
        cleanupCaptureSession();
        m_initialized = false;
    }
}

bool AVFoundationControl::getZoomCapabilities(ZoomCapabilities& caps) {
    if (!m_initialized || !m_device) return false;
    
    @autoreleasepool {
        AVCaptureDevice* device = (AVCaptureDevice*)m_device;
        
        caps.min = static_cast<int>(device.minAvailableVideoZoomFactor * 100);
        caps.max = static_cast<int>(device.maxAvailableVideoZoomFactor * 100);
        caps.step = 1; // AVFoundation uses continuous values
        caps.current = static_cast<int>(device.videoZoomFactor * 100);
        caps.supportsAbsolute = true;
        caps.supportsRelative = true;
        
        return true;
    }
}

bool AVFoundationControl::setZoomAbsolute(int value) {
    if (!m_initialized || !m_device) return false;
    
    @autoreleasepool {
        AVCaptureDevice* device = (AVCaptureDevice*)m_device;
        
        // Convert from integer percentage to float factor
        CGFloat zoomFactor = static_cast<CGFloat>(value) / 100.0;
        
        // Clamp to device limits
        zoomFactor = MAX(device.minAvailableVideoZoomFactor, 
                        MIN(device.maxAvailableVideoZoomFactor, zoomFactor));
        
        NSError* error = nil;
        if (![device lockForConfiguration:&error]) {
            return false;
        }
        
        device.videoZoomFactor = zoomFactor;
        [device unlockForConfiguration];
        
        return true;
    }
}

bool AVFoundationControl::setZoomRelative(int value) {
    if (!m_initialized || !m_device) return false;
    
    @autoreleasepool {
        AVCaptureDevice* device = (AVCaptureDevice*)m_device;
        
        // Get current zoom and adjust
        CGFloat currentZoom = device.videoZoomFactor;
        CGFloat deltaZoom = static_cast<CGFloat>(value) / 100.0;
        CGFloat newZoom = currentZoom + deltaZoom;
        
        // Clamp to device limits
        newZoom = MAX(device.minAvailableVideoZoomFactor, 
                     MIN(device.maxAvailableVideoZoomFactor, newZoom));
        
        NSError* error = nil;
        if (![device lockForConfiguration:&error]) {
            return false;
        }
        
        device.videoZoomFactor = newZoom;
        [device unlockForConfiguration];
        
        return true;
    }
}

bool AVFoundationControl::getZoomValue(int& value) {
    if (!m_initialized || !m_device) return false;
    
    @autoreleasepool {
        AVCaptureDevice* device = (AVCaptureDevice*)m_device;
        value = static_cast<int>(device.videoZoomFactor * 100);
        return true;
    }
}

#endif // __APPLE__