import SwiftUI
import AVKit

public typealias CaptureViewSignalToEndAction = () -> Void

public struct CaptureView: View {
    
    @ObservedObject var captureCoordinator: CaptureCoordinator
    
    let onCapturePhoto: (URL) -> Void
    let onCaptureVideo: (URL) -> Void
    let onCaptureAudio: (URL) -> Void
    let onComposeVideoAndAudio: (URL) -> Void
    
    public init(_ captureCoordinator: CaptureCoordinator,
        onCapturePhoto: @escaping (URL) -> Void,
        onCaptureVideo: @escaping (URL) -> Void,
        onCaptureAudio: @escaping (URL) -> Void,
        onComposeVideoAndAudio: @escaping (URL) -> Void) {
        
        self.captureCoordinator = captureCoordinator
        self.onCapturePhoto = onCapturePhoto
        self.onCaptureVideo = onCaptureVideo
        self.onCaptureAudio = onCaptureAudio
        self.onComposeVideoAndAudio = onComposeVideoAndAudio
    }
    
    public var body: some View {
        PreviewMetalViewRepresentable(
            videoCaptureCoordinator: captureCoordinator.videoCaptureCoordinator,
            audioCaptureCoordinator: captureCoordinator.audioCaptureCoordinator,
            previewCoordinator: captureCoordinator.previewCoordinator,
            uniformScale: $captureCoordinator.zoom)
            .onAppear {
                videoCapture.start()
            }
            .onDisappear {
                videoCapture.end()
                audioCapture.resetAudioSessionForPlayback()
            }
            .onChange(of: captureCoordinator.capturedVideoURL) { oldValue, newValue in
                guard let newValue else { return }
                onCaptureVideo(newValue)
                guard shouldComposeOnCapture else { return }
                captureCoordinator.composeVideoAndAudioIfAvailable()
            }
            .onChange(of: captureCoordinator.capturedPhotoURL) { oldValue, newValue in
                guard let newValue else { return }
                onCapturePhoto(newValue)
            }
            .onChange(of: captureCoordinator.capturedAudioURL) { oldValue, newValue in
                guard let newValue else { return }
                onCaptureAudio(newValue)
                guard shouldComposeOnCapture else { return }
                captureCoordinator.composeVideoAndAudioIfAvailable()
            }
            .onChange(of: captureCoordinator.composedVideoWithAudio) { oldValue, newValue in
                guard let newValue else { return }
                onComposeVideoAndAudio(newValue)
            }
    }
}

private extension CaptureView {
    var videoCapture: VideoCaptureCoordinator {
        return captureCoordinator.videoCaptureCoordinator
    }
    
    var audioCapture: AudioCaptureCoordinator {
        return captureCoordinator.audioCaptureCoordinator
    }
    
    var shouldComposeOnCapture: Bool {
        return captureCoordinator.captureOptions.contains(.shouldComposeOnCapture)
    }
 }
