//
//  BGVideoImageMolecule.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 1/26/21.
//  Copyright © 2021 Verizon Wireless. All rights reserved.
//

import UIKit

open class BGVideoImageMolecule: BGImageMolecule {

    public let video = Video()
    
    /// Used to hide video after loaded.
    private var stateKVOToken: NSKeyValueObservation?
    private var endObserver: NSObjectProtocol?
    
    open override func setupView() {
        super.setupView()
        insertSubview(video, aboveSubview: image)
        NSLayoutConstraint.constraintPinSubview(toSuperview: video)
    }
    
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        guard let model = model as? BGVideoImageMoleculeModel else { return }
        video.set(with: model.video, delegateObject, additionalData)
        video.isHidden = shouldVideoBeHidden()
        addStateObserver()
    }
    
    open func shouldVideoBeHidden() -> Bool {
        guard let model = model as? BGVideoImageMoleculeModel,
              model.video.videoDataManager.videoState != .failed else {
            return true
        }
        guard model.video.videoDataManager.videoState == .loaded,
           let player = model.video.videoDataManager.player,
           let item = player.currentItem,
           item.currentTime() == item.duration else {
            return false
        }
        return true
    }
    
    /// Listens and responds to video loading state changes to add the end observer.
    private func addStateObserver() {
        removeStateObserver()

        guard stateKVOToken == nil,
              let model = model as? BGVideoImageMoleculeModel else { return }
        
        // To know when the video player item is done loading.
        stateKVOToken =
            model.video.videoDataManager.observe(\.videoState) { [weak self] (item, change) in
            guard let self = self,
                  let model = self.model as? BGVideoImageMoleculeModel,
                  item == model.video.videoDataManager else { return }
                
            switch item.videoState {
            case .loaded:
                self.addEndObserver()
            case .failed:
                MVMCoreDispatchUtility.performBlock(onMainThread: {
                    self.video.isHidden = true
                })
            default:
                break
            }
        }
    }

    private func removeStateObserver() {
        stateKVOToken?.invalidate()
        stateKVOToken = nil
    }
    
    private func addEndObserver() {
        removeStateObserver()
        guard let model = model as? BGVideoImageMoleculeModel,
              let item = model.video.videoDataManager.player?.currentItem else { return }
        endObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: item, queue: OperationQueue.main) { [weak self] (notification) in
            self?.video.isHidden = true
        }
    }
    
    private func removeEndObserver() {
        guard let endObserver = endObserver else { return }
        NotificationCenter.default.removeObserver(endObserver)
        self.endObserver = nil
    }
    
    deinit {
        removeStateObserver()
        removeEndObserver()
    }
}
