//
//  StreamingService.swift
//  IosTemplate
//
//  Created by Ereeny on 7/16/17.
//  Copyright © 2017 ExtremeSolution. All rights reserved.
//

import UIKit
import Foundation
import AVFoundation
import MediaPlayer

@objc(StreamingService)

class StreamingService: NSObject {

  static let shared = StreamingService()

  fileprivate var player : AVPlayer? = nil
  var playerItem : AVPlayerItem? = nil
  fileprivate var seekDuration: Float64 = 10

  fileprivate var urlString : String = ""
  var playing = false
  var Muted = false


  var commandCenter = MPRemoteCommandCenter.shared()

  var metaDataDidChange: ((_ metadata:[AVMetadataItem]?) -> Void)?

  @objc func connectWithURL(url:String){
    if (self.player == nil) {

      urlString =  url

      self.handleLockScreen(title: "Radio", subtitle: "Now playing", currentIMG: nil)
      let notificationNameCall = Notification.Name("resumeAfterCall")

      NotificationCenter.default.addObserver(self, selector: #selector(self.handleNotificationResumeAfterCall), name: notificationNameCall, object: nil)

      NotificationCenter.default.addObserver(self,
                                             selector: #selector(self.handleNotificationResumeAfterCall),
                                             name: NSNotification.Name.AVAudioSessionInterruption,
                                             object: nil)

      NotificationCenter.default.addObserver(self, selector: #selector(playerItemFailedToPlay), name: NSNotification.Name.AVPlayerItemFailedToPlayToEndTime, object: nil)


      NotificationCenter.default.addObserver(self,
                                             selector: #selector(StreamingService.updateLockScreen(notification:)),
                                             name: NSNotification.Name(rawValue: "lockScreen"),
                                             object: nil)
      MPRemoteCommandCenter.shared().pauseCommand.addTarget { (e) -> MPRemoteCommandHandlerStatus in
        self.pause();
        return MPRemoteCommandHandlerStatus.success;
      }
      MPRemoteCommandCenter.shared().playCommand.addTarget { (e) -> MPRemoteCommandHandlerStatus in
        self.play(url: self.urlString);
        return MPRemoteCommandHandlerStatus.success;
      }
    }
  }

  func playerItemFailedToPlay(notification: Notification) {

    let error = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? Error
    player?.pause()

    self.perform(#selector(resetPlayer), with: nil, afterDelay: 2)
  }

  func resetPlayer() {
    self.pause()
    player = nil;
    NotificationCenter.default.removeObserver(self)
    playerItem?.removeObserver(self, forKeyPath: "timedMetadata")
    player?.removeTimeObserver(self)
    self.connectWithURL(url: urlString)
  }

  func updateLockScreen(notification:NSNotification) {
    // print(notification.object ?? "KOLOKOLOKOLO")
    if let object = notification.object as? Dictionary<String, Any>{


      guard let url = URL(string: object["image"] as! String) else {
        handleLockScreen(title: object["Show"] as? String, subtitle: object["Song"] as? String, currentIMG: nil)
        return
      }
      let data = try? Data(contentsOf: url)
      if data != nil {
        if let image = UIImage(data: data!){
          handleLockScreen(title: object["Show"] as? String, subtitle: object["Song"] as? String, currentIMG: image)
        }
      }
    }
  }

  @objc func setVolume(value:Float) {

    let volumeSlider: MPVolumeView = MPVolumeView()
    if let view = volumeSlider.subviews.first as? UISlider{

      view.value = value
    }
  }

  @objc func getVolume() -> Float {
    let volume = Double(AVAudioSession.sharedInstance().outputVolume)


    return Float(volume)
  }

  @objc  func play(url: String){
    if(player == nil){

      playerItem = AVPlayerItem( url:NSURL( string:urlString )! as URL )
      player = AVPlayer(playerItem:playerItem)
      playerItem?.addObserver(self, forKeyPath: "timedMetadata", options: NSKeyValueObservingOptions.new, context: nil)
    }

    if(player == nil)
    {
      return
    }

    player?.play()
    playing = true

    do {
      try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)

      do {
        try AVAudioSession.sharedInstance().setActive(true)
        //        // print("AVAudioSession is Active")
      } catch let error as NSError {
        // print(error.localizedDescription)
      }
    } catch let error as NSError {
      // print(error.localizedDescription)
    }

    self.sendPlaybackStateMsg(state: 1);
  }

  @objc func pause(){
    if(player == nil) {
      return
    }

    player?.pause()
    playing = false

    self.sendPlaybackStateMsg(state: 2);
  }

  func sendPlaybackStateMsg(state: Int){
    let dict:[String: Int] = ["status": state]
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "CB_PLAYBACKSTATE"), object: nil, userInfo: dict)
  }

  @objc func mute(){
    if(player == nil) {
      return
    }
    player?.isMuted =  true
    Muted = true
  }

  @objc func unMute() {
    if(player == nil) {
      return
    }
    player?.isMuted = false
    Muted = false
  }

  @objc func backward() {
    if(player == nil) {
      return
    }

    let playerCurrentTime = CMTimeGetSeconds((player?.currentTime())!)
    var newTime = playerCurrentTime - self.seekDuration
    if newTime < 0 {
      newTime = 0
    }
    let time2: CMTime = CMTimeMake(Int64(newTime * 1000 as Float64), 1000)
    player?.seek(to: time2, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
  }

  @objc func forward() {
    if(player == nil){
      return
    }

    let playerCurrentTime = CMTimeGetSeconds((player?.currentTime())!)
    let newTime = playerCurrentTime + self.seekDuration
    let timeRange = player?.currentItem?.loadedTimeRanges[0].timeRangeValue
    let duration = CMTimeGetSeconds((timeRange?.duration)!)

    if newTime < (duration) {
      let time2: CMTime = CMTimeMake(Int64(newTime * 1000 as Float64), 1000)
      player?.seek(to: time2, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
    }
  }



  @objc fileprivate func handleNotificationResumeAfterCall(notification: NSNotification){
    if notification.name == NSNotification.Name.AVAudioSessionInterruption {

      let began : AnyObject? = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as AnyObject?
      if let began = began as? UInt {
        if let began = AVAudioSessionInterruptionType(rawValue: began) {
          if began == .began {

          } else {
            if self.playing {
              self.play(url: urlString);
            } else {
              self.pause();
            }
          }
        }
      }
    }
  }

  @objc func handleLockScreen(title:String?,subtitle:String? ,currentIMG: UIImage?){

    commandCenter.previousTrackCommand.isEnabled = false

    var nowPlaying : [String : Any] = [MPMediaItemPropertyAlbumTitle: subtitle ?? "",
                                       MPMediaItemPropertyTitle: title ?? "",
                                       MPNowPlayingInfoPropertyPlaybackRate: NSNumber(value: 1.0)]

    if currentIMG != nil {
      nowPlaying[MPMediaItemPropertyArtwork] =  MPMediaItemArtwork(image: currentIMG!)
    }

    MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlaying
    UIApplication.shared.beginReceivingRemoteControlEvents()
  }


  override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "timedMetadata" {
      if let metaDataDidChange = self.metaDataDidChange{
        metaDataDidChange(playerItem?.timedMetadata)
      }
    }
  }

  @objc func isPlaying() -> Bool {
    if ((player?.rate != 0) && (player?.error == nil)) {
      return true
    }
    return false
  }
  
  deinit {
    
    NotificationCenter.default.removeObserver(self)
    playerItem?.removeObserver(self, forKeyPath: "timedMetadata")
  }
}
