//
//  OasisPlayerViewController.swift
//  OasisPlayerPlugin
//
//  Created by MSApps on 04/05/2020.
//

import UIKit
import OasisPlayer
import ZappPlugins
import GoogleCast
//import SevenOneAds
import ZappCore

class OasisPlayerViewController: UIViewController {

    @IBOutlet private var playerContainerView: UIView!
    @IBOutlet private var CloseBtnOutlet: UIButton!
    @IBOutlet private var chromeCastContainer: UIView!
    @IBOutlet private var blackView: UIView!
    @IBOutlet private var connectToDeviceLabel: UILabel!
    
    private let currentPlayable: Playable
    private let oasisEnvironment: OasisEnvironment
    private let somConfig: SOMConfig
    private let playbackListener = PlaybackStateListener() // listener for getting current clip position
    private let trackingDelegate = OasisPlayerTrackingDelegate() // delegate instance for sending player event
    private var extendedPlayerViewController: UIViewController?
    private var player: OasisPlayer?
    
    var isFullScreen = false
    
    private var isCurrentlyVisible = false
    private var isChromecastSynced: Bool {
        return FacadeConnector.connector?.chromecast?.isSynced ?? false
    }
    
    internal var onVideoEnd: () -> Void = {}
    
    // MARK: Applicastion Life Cycle
    
    init(playable: Playable,
         oasisEnvironment: OasisEnvironment,
         somConfig: SOMConfig) {
        self.currentPlayable = playable
        self.oasisEnvironment = oasisEnvironment
        self.somConfig = somConfig
        
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        removeChromecastObservers()
    }
    
    // TODO: Call on deinit
    
    public func destoryPlayer() {
        player?.removeUI(playbackListener)
        player?.destroy()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        createPlayer()
        createCastButton()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        addChromecastObservers()
        isCurrentlyVisible = true

        if isChromecastSynced == false {
            player?.play()
        }
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        if isChromecastSynced == false {
            player?.pause()
        }
        
        removeChromecastObservers()
        isCurrentlyVisible = false
        
        super.viewDidDisappear(animated)
    }
    
    func createPlayer(){
        oasisEnvironment.createPlayer(completion: { [weak self] (playerInstance, error) in
            guard let self = self,
                  let player = playerInstance,
                  let videoId = self.currentPlayable.isLive ? self.currentPlayable.clipID : self.currentPlayable.sourceDictionary.value(forKey: "id"),
                  error == nil else {
                return
            }
            
            self.player = player
            player.isDefaultAirPlayControlEnabled = true
            let videoView = player.getPlayerView()
            self.playerContainerView.addSubview(videoView)
            videoView.translatesAutoresizingMaskIntoConstraints = false
            let views:[String:UIView] = ["self": videoView]
            self.playerContainerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[self]|",
                                                                                   options: NSLayoutConstraint.FormatOptions(rawValue: 0),
                                                                                   metrics: nil,
                                                                                   views: views))
            self.playerContainerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[self]|",
                                                                                   options: NSLayoutConstraint.FormatOptions(rawValue: 0),
                                                                                   metrics: nil,
                                                                                   views: views))
            // if live stream had ability for full screen
            if self.currentPlayable.isLive {
                player.setFullscreenViewController(sourceController: self, targetController: nil)
            }
            
            // contant info for player
            var contentResource = [
                ContentResource.contentType: self.currentPlayable.isLive ? "live" : "vod",
                ContentResource.id: videoId,
                ContentResource.title: self.currentPlayable.title ?? ""] as [String : Any]
            
//            contentResource[SOMPlugin.Keys.ContentResource.adRollOffsets] = somConfig.ads
//            var somMarketing: [String: Any] = [:]
//            somMarketing[SOMPlugin.Keys.SOMMarketing.domain] = somConfig.domain
//            if self.somConfig.domain != self.somConfig.subdomain {
//                somMarketing[SOMPlugin.Keys.SOMMarketing.subdomain] = somConfig.subdomain
//            }
//            somMarketing[SOMPlugin.Keys.SOMMarketing.isLongPlay] = somConfig.isLongPlay
//            contentResource[SOMPlugin.Keys.ContentResource.somMarketing] = somMarketing
            
            if let trackingDictionary = self.currentPlayable.tracking,
               trackingDictionary.count != 0 {
                contentResource["trackingMetadata"] = trackingDictionary
            }
            
            player.add(trackerInterface: self.trackingDelegate)
            player.defaultUi?.delegate = self
            player.addContentResource(contentResource)
            player.setPlaylistIndex(0)
            player.addUI(self.playbackListener)
            
            
            let facadeConnector = FacadeConnector.connector
            let connectivityState = facadeConnector?.connectivity?.getCurrentConnectivityState() ?? .offline
            
            //If the device is sync to chromecast it means that your'e connected via wifi
            if(self.isChromecastSynced) {
                self.castCurrentStream()
                self.openChromecastPlayer(shouldPresentFullScreen: false)
            } else {
                self.blackView.isHidden = true
                if connectivityState == .wifi, self.isCurrentlyVisible {
                    player.play()
                }
            }
        })
    }
    
    @IBAction func closeBtnDidTap(_ sender: UIButton) {
        onVideoEnd()
        self.dismiss(animated: true, completion: nil)
    }
    
    // MARK: Charomeacst
    
    @objc func chromecastSessionDidStart(notification: NSNotification) {
        castCurrentStream()
    }
    
    @objc func chromecastSessionDidEnd(notification: NSNotification){
        //Let's keep it for the future, just in case.
    }
    
    @objc func chromecastSessionWillEnd(notification: NSNotification){
        let STREAM_POSITION = "streamPosition"
        
        if let notificationObject = notification.object as? [String:Any],
           let position = notificationObject[STREAM_POSITION] as? Double{
            self.player?.seekTo(position)
        }
        self.player?.play()
        blackView.isHidden = true
    }
    
    @objc func chromecastStartedPlaying(notification: NSNotification){
        openChromecastPlayer(shouldPresentFullScreen: true)
    }
    
    @objc func chromecastPlayingError(notification: NSNotification) {
        //Let's keep it for the future, just in case.
    }
    
    @objc func castDeviceDidChange(_ notification:Notification) {
        switch (GCKCastContext.sharedInstance().castState) {
        case .notConnected:
            break
        case .connected:
            self.openChromecastPlayer(shouldPresentFullScreen: true)
            break
        default:
            break
        }
    }
    
    private func createCastButton() {
        guard let chromecast = FacadeConnector.connector?.chromecast else {
            return
        }
        
        chromecast.addButton(to: chromeCastContainer,
                             key: "chrome",
                             color: nil)
    }
    
    private func addChromecastObservers(){
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(chromecastSessionDidStart),
                                               name:  NSNotification.Name.chromecastSessionDidStart,
                                               object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(chromecastSessionWillEnd),
                                               name:  NSNotification.Name.chromecastSessionWillEnd,
                                               object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(chromecastSessionDidEnd),
                                               name:  NSNotification.Name.chromecastSessionDidEnd,
                                               object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(chromecastStartedPlaying),
                                               name:  NSNotification.Name.chromecastStartedPlaying,
                                               object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(chromecastPlayingError),
                                               name:  NSNotification.Name.chromecastPlayingError,
                                               object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(castDeviceDidChange(_:)),
                                               name: NSNotification.Name.gckCastStateDidChange,
                                               object: nil)
    }
    
    private func removeChromecastObservers(){
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.chromecastSessionDidStart, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.chromecastSessionWillEnd, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.chromecastSessionDidEnd, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.chromecastStartedPlaying, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.chromecastPlayingError, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.gckCastStateDidChange, object: nil)
    }
    
    func openChromecastPlayer(shouldPresentFullScreen: Bool) {
        guard let chromecast = FacadeConnector.connector?.chromecast else {
            return
        }
        //Full Screen
        if self.isFullScreen {
            if shouldPresentFullScreen {
                if (self.extendedPlayerViewController == nil) {
                    let extendedPlayerViewController = chromecast.extendedPlayerViewController
                    self.addChildViewController(extendedPlayerViewController, to: self.view)
                    extendedPlayerViewController?.view.matchParent()
                    self.extendedPlayerViewController = extendedPlayerViewController
                    self.destoryPlayer()
                }
            }
        } else { //Inline Player
            if let deviceName = GCKCastContext.sharedInstance().sessionManager.currentSession?.device.friendlyName {
                self.connectToDeviceLabel.text = "Connected to \(deviceName)"
            }
            self.blackView.isHidden = false
            self.player?.pause()
        }
    }
    
    func castCurrentStream() {
        guard let chromecast = FacadeConnector.connector?.chromecast else {
            return
        }

        chromecast.play(with: [currentPlayable.sourceDictionary],
                        playPosition: playbackListener.currentPosition ?? 0.0,
                        completion: nil)
    }
}

extension OasisPlayerViewController: OasisUIPlayerControlsDelegate {
    // default controls UI hidden state
    func visibilityUpdated(_ controls: OasisUIPlayerControls, hidden: Bool) {
        CloseBtnOutlet.alpha = hidden ? 0.0 : 1.0
        chromeCastContainer.alpha = hidden ? 0.0 : 1.0
    }
}
