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

import Foundation

open class VideoModel: MoleculeModelProtocol, PageBehaviorProtocolRequirer {
    public static var identifier = "video"
    public var backgroundColor: Color?
    public var video: String
    public var showControls = false
    public var autoPlay = true
    public var alwaysReset = false
    weak public var view: Video?

    /// When the video is halted because it is no longer visible
    public var halted: Bool = false {
        didSet {
            guard halted != oldValue,
                  videoDataManager.videoState == .loaded else { return }
            if halted {
                videoDataManager.player?.pause()
            } else {
                if alwaysReset {
                    // Always start video at the beginning.
                    videoDataManager.player?.seek(to: .zero)
                }
                if autoPlay {
                    videoDataManager.player?.play()
                }
            }
        }
    }

    /// Keeps a reference to the video data.
    public var videoDataManager: VideoDataManager
    
    private var activeListener: Any?
    private var resignActiveListener: Any?

    private enum CodingKeys: String, CodingKey {
        case moleculeName
        case video
        case showControls
        case autoPlay
        case alwaysReset
    }

    public init(_ video: String) {
        self.video = video
        videoDataManager = VideoDataManager(with: video)
    }

    required public init(from decoder: Decoder) throws {
        let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
        video = try typeContainer.decode(String.self, forKey:.video)
        if let showControls = try typeContainer.decodeIfPresent(Bool.self, forKey: .showControls) {
            self.showControls = showControls
        }
        if let autoPlay = try typeContainer.decodeIfPresent(Bool.self, forKey: .autoPlay) {
            self.autoPlay = autoPlay
        }
        if let alwaysReset = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysReset) {
            self.alwaysReset = alwaysReset
        }
        videoDataManager = VideoDataManager(with: video)
    }

    open func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(moleculeName, forKey: .moleculeName)
        try container.encode(video, forKey: .video)
        try container.encode(showControls, forKey: .showControls)
        try container.encode(autoPlay, forKey: .autoPlay)
        try container.encode(alwaysReset, forKey: .alwaysReset)
    }
    
    public func getRequiredBehaviors() -> [PageBehaviorModelProtocol] {
        return [VisibleBehaviorForVideoModel(with: self)]
    }
    
    open func addVisibilityHalting(for view: Video, delegateObject: MVMCoreUIDelegateObject?) {
        self.view = view
        halted = false
        addActiveListener(for: view, delegateObject: delegateObject)
    }
    
    open func addActiveListener(for view: Video, delegateObject: MVMCoreUIDelegateObject?) {
        removeActiveListener()
        
        resignActiveListener = NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: OperationQueue.main) { [weak self] (notification) in
            self?.halted = true
        }
        activeListener = NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: OperationQueue.main) { [weak self] (notification) in
            guard let self = self,
                  let view = self.view,
                  view.isVisibleInDelegate() else { return }
            self.halted = false
        }
    }
    
    private func removeActiveListener() {
        if let observer = activeListener {
            NotificationCenter.default.removeObserver(observer)
            activeListener = nil
        }
        if let observer = resignActiveListener {
            NotificationCenter.default.removeObserver(observer)
            resignActiveListener = nil
        }
    }
    
    deinit {
        removeActiveListener()
    }
}
