import Foundation
import UIKit
import Postbox
import TelegramCore
import SyncCore
import SwiftSignalKit
import CoreMedia
import UniversalMediaPlayer

private final class RunningSoftwareVideoSource {
    let fetchDisposable: Disposable
    let fetchStatusDisposable: Disposable
    
    var source: SoftwareVideoSource?
    var beginTime: Double?
    var frame: MediaTrackFrame?
    
    init(fetchDisposable: Disposable, fetchStatusDisposable: Disposable) {
        self.fetchDisposable = fetchDisposable
        self.fetchStatusDisposable = fetchStatusDisposable
    }
    
    deinit {
        self.fetchDisposable.dispose()
        self.fetchStatusDisposable.dispose()
    }
}

final class MultiplexedSoftwareVideoSourceManager {
    private let queue: Queue
    private let account: Account
    private var videoSources: [MediaId: RunningSoftwareVideoSource] = [:]
    private(set) var immediateVideoFrames: [MediaId: MediaTrackFrame] = [:]
    
    private var updatingAt: Double?
    
    var updateFrame: ((MediaId, MediaTrackFrame) -> Void)?
    
    init(queue: Queue, account: Account) {
        self.queue = queue
        self.account = account
    }
    
    func updateVisibleItems(_ media: [TelegramMediaFile]) {
        self.queue.async {
            var dict: [MediaId: TelegramMediaFile] = [:]
            for file in media {
                dict[file.fileId] = file
            }
            
            var removeIds: [MediaId] = []
            for id in self.videoSources.keys {
                if dict[id] == nil {
                    removeIds.append(id)
                }
            }
            
            for id in removeIds {
                self.videoSources.removeValue(forKey: id)
            }
            
            for (id, file) in dict {
                if self.videoSources[id] == nil {
                    self.videoSources[id] = RunningSoftwareVideoSource(fetchDisposable: (self.account.postbox.mediaBox.resourceData(file.resource) |> deliverOn(self.queue)).start(next: { [weak self] data in
                        if let strongSelf = self, let context = strongSelf.videoSources[id] {
                            if data.complete {
                                context.source = SoftwareVideoSource(path: data.path)
                            }
                        }
                    }), fetchStatusDisposable: fetchedMediaResource(mediaBox: self.account.postbox.mediaBox, reference: AnyMediaReference.standalone(media: file).resourceReference(file.resource)).start())
                }
            }
        }
    }
    
    func update(at timestamp: Double) {
        assert(Queue.mainQueue().isCurrent())
        let begin = self.updatingAt == nil
        self.updatingAt = timestamp
        if begin {
            self.queue.async {
                var immediateVideoFrames: [MediaId: MediaTrackFrame] = [:]
                loop: for (id, source) in self.videoSources {
                    if let context = source.source {
                        if let beginTime = source.beginTime, let currentFrame = source.frame {
                            let framePosition = currentFrame.position.seconds
                            let frameDuration = currentFrame.duration.seconds
                            
                            if false && beginTime + framePosition + frameDuration > timestamp {
                                immediateVideoFrames[id] = currentFrame
                                continue loop
                            }
                        }
                        
                        /*if let frame = context.readFrame(maxPts: nil) {
                            if source.frame == nil || CMTimeCompare(source.frame!.position, frame.position) > 0 {
                                source.beginTime = timestamp
                            }
                            source.frame = frame
                            immediateVideoFrames[id] = frame
                            self.updateFrame?(id, frame)
                        }*/
                    }
                }
                
                Queue.mainQueue().async {
                    self.immediateVideoFrames = immediateVideoFrames
                    if let updatingAt = self.updatingAt, !updatingAt.isEqual(to: timestamp) {
                        self.updatingAt = nil
                        self.update(at: updatingAt)
                    } else {
                        self.updatingAt = nil
                    }
                }
            }
        }
    }
}