//
//  ViewController.swift
//  Runner
//
//  Created by  Mohammad Aljammal  & Elham Rababah on 23/6/20.
//  Copyright © 2020 The Chromium Authors. All rights reserved.
//

import UIKit
import OpenTok
import Alamofire
import AADraggableView

class VideoCallViewController: UIViewController {
    
    var session: OTSession?
    var publisher: OTPublisher?
    var subscriber: OTSubscriber?
    
    var kApiKey:String = ""
    
    var kSessionId:String = ""
    
    var kToken:String = ""
    
    var VC_ID: Int = 0
    var TokenID: String = ""
    var generalid : String = ""
    var DoctorId: Int = 0
    var baseUrl:String = ""
    
    var callBack: ICallProtocol?
    var timer = Timer()
    var seconds = 55 
    var isUserConnect : Bool = false
    
    var onRectFloat:((Bool)->Void)? = nil
    var onCircleFloat:((Bool)->Void)? = nil
    var onCallConnect:(()->Void)? = nil
    var onCallDisconnect:(()->Void)? = nil

    
    @IBOutlet weak var lblRemoteUsername: UILabel!
    
    // Bottom Actions
    @IBOutlet weak var videoMuteBtn: UIButton!
    @IBOutlet weak var micMuteBtn: UIButton!
    @IBOutlet weak var camSwitchBtn: UIButton!
    
    @IBOutlet var minimizeConstraint: [NSLayoutConstraint]!
    @IBOutlet var maximisedConstraint: [NSLayoutConstraint]!

    @IBOutlet weak var btnMinimize: UIButton!
    @IBOutlet weak var hideVideoBtn: UIButton!
    var localVideoDraggable:AADraggableView?
    @IBOutlet weak var controlButtons: UIView!
    @IBOutlet weak var remoteVideoMutedIndicator: UIImageView!
    @IBOutlet weak var localVideoMutedBg: UIView!
    
    @IBOutlet weak var btnScreenTap: UIButton!
    @IBOutlet weak var localVideoContainer: UIView!
    @IBOutlet weak var topBar: UIView!
    @IBOutlet weak var lblCallDuration: UILabel!
    @IBOutlet weak var fullVideoView: UIView!
    @IBOutlet weak var smallVideoView: UIView!{
        didSet{
            smallVideoView.layer.borderColor = UIColor.white.cgColor
            localVideoDraggable = smallVideoView?.superview as? AADraggableView
            localVideoDraggable?.reposition = .edgesOnly
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        localVideoDraggable?.respectedView = localVideoContainer
    }
    
    @objc func click(gesture:UIGestureRecognizer){
        gesture.view?.removeFromSuperview()
    }
    
    @IBAction func btnOnScreenTapped(_ sender: Any) {
        if(hideVideoBtn.isSelected){
            circleFloatBtnTapped(hideVideoBtn)
            
        }else if(btnMinimize.isSelected){
            btnMinimizeTapped(btnMinimize)
        }
    }
    
    @IBAction func btnSwipeVideoTapped(_ sender: Any) {
//        let smallVdoRender = smallVideoView.subviews.first
//        let fullVdoRender = fullVideoView.subviews.first
//        if let vdo = smallVdoRender{
//            fullVideoView.addSubview(vdo)
//        }
//        if let vdo = fullVdoRender{
//            smallVideoView.addSubview(vdo)
//        }
//
//        layoutVideoRenderViews()
    }
    
    @IBAction func didClickMuteButton(_ sender: UIButton) {
        sender.isSelected = !sender.isSelected
        publisher!.publishAudio = !sender.isSelected
    }
    
    @IBAction  func didClickSpeakerButton(_ sender: UIButton) {
         sender.isSelected = !sender.isSelected
         subscriber?.subscribeToAudio = !sender.isSelected
     }

   @IBAction  func didClickVideoMuteButton(_ sender: UIButton) {
         sender.isSelected = !sender.isSelected
    if publisher!.publishVideo {
            publisher!.publishVideo = false
         } else {
            publisher!.publishVideo = true
         }
         smallVideoView.isHidden = sender.isSelected
         localVideoMutedBg.isHidden = !sender.isSelected

     }
    
    
    @IBAction func didClickSwitchCameraButton(_ sender: UIButton) {
        sender.isSelected = !sender.isSelected
        if sender.isSelected {
            publisher!.cameraPosition = AVCaptureDevice.Position.front
        } else {
            publisher!.cameraPosition = AVCaptureDevice.Position.back
        }
    }

    @IBAction func hangUp(_ sender: UIButton) {
        callBack?.sessionDone(res:["callResponse":"CallEnd"])
        sessionDisconnect()
    }
    
    @IBAction func circleFloatBtnTapped(_ sender: UIButton) {
        sender.isSelected = !sender.isSelected
        onCircleFloat?(sender.isSelected)
        topBar.isHidden = sender.isSelected
        controlButtons.isHidden = sender.isSelected
        smallVideoView.isHidden = sender.isSelected
        self.publisher?.view?.layoutIfNeeded()
    }

    @IBAction func btnMinimizeTapped(_ sender: UIButton) {
        minimizeVideoState(state: !sender.isSelected)
        btnScreenTap.isHidden = !sender.isSelected
    }
    
    func minimizeVideoState(state:Bool){
        btnMinimize.isSelected = state
        onRectFloat?(state)
        
        NSLayoutConstraint.activate(state ? minimizeConstraint : maximisedConstraint)
        NSLayoutConstraint.deactivate(state ? maximisedConstraint : minimizeConstraint)
        localVideoDraggable?.enable(!state)
        
        lblRemoteUsername.isHidden = state
        hideVideoBtn.isHidden = !state
        lblCallDuration.superview?.isHidden = !hideVideoBtn.isHidden
        
        UIView.animate(withDuration: 0.5) {
            self.videoMuteBtn.isHidden = state
            self.micMuteBtn.isHidden = state
            self.camSwitchBtn.isHidden = state
            self.layoutVideoRenderViews()
        }
    }
    
    func layoutVideoRenderViews(){
        if let publisherVdoSize = publisher?.view?.superview?.bounds.size{
            publisher?.view?.frame = CGRect(x: 0, y: 0, width: publisherVdoSize.width, height: publisherVdoSize.height)
        }
        if let subscriberVdoSize = subscriber?.view?.superview?.bounds.size{
            subscriber?.view?.frame = CGRect(x: 0, y: 0, width: subscriberVdoSize.width, height: subscriberVdoSize.height)
        }
    }
    
    var durationTimer:Timer?;
    func startUpdateCallDuration(){
        var seconds = 0
        durationTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
            seconds = seconds+1
            let durationSegments = (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
            let hours = String(format: "%02d", durationSegments.0)
            let mins = String(format: "%02d", durationSegments.1)
            let secs = String(format: "%02d", durationSegments.2)
            let durationString = "\(mins):\(secs)"
            
            self.lblCallDuration.text = durationString
        }
    }
    
    func start(params:VideoCallRequestParameters){
        lblRemoteUsername.text = params.patientName ?? "- - -"
        btnScreenTap.isHidden = true
        hideVideoBtn.isHidden = true
        
        self.kApiKey = params.apiKey ?? ""
        self.kSessionId = params.sessionId ?? ""
        self.kToken = params.token ?? ""
        self.VC_ID = params.vcId ?? 0
        self.generalid = params.generalId ?? ""
        self.TokenID = params.tokenId ?? ""
        self.DoctorId = params.doctorId ?? 0
        self.baseUrl = params.baseUrl ?? ""
        
        askForMicrophonePermission()
        requestCameraPermissionsIfNeeded()
        hideVideoMuted()
        setupSession()
        
    }
    
    private func changeCallStatus(callStatus:Int){
        let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/ChangeCallStatus"
        let headers: HTTPHeaders = ["Content-Type":"application/json","Accept":"application/json",]
        
        let parameters = [
            "CallStatus":callStatus,
            "VC_ID": VC_ID,
            "TokenID": TokenID,
            "generalid": generalid,
            "DoctorId" : DoctorId ,
            ] as [String : Any]
        
        AF.request(URL_USER_REGISTER, method: .post,parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON{
                response in
            if let result = response.value {
                let jsonData = result as! NSObject
                let resultVal = jsonData.value(forKey: "Result")
                print(resultVal as Any)
            }
            
        }
    }
    
    private func getSessionStatus() {
            let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/GetSessionStatus"
            let headers: HTTPHeaders = [
                "Content-Type":"application/json",
                "Accept":"application/json",
                
            ]
            
            let parameters = [
                "VC_ID": VC_ID,
                "TokenID": TokenID,
                "generalid": generalid,
                "DoctorId" : DoctorId ,
                ] as [String : Any]
        AF.request(URL_USER_REGISTER, method: .post,parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON{
                    response in
                if self.isUserConnect {
                } else {
                    if let result = response.value {
                        let jsonData = result as! NSObject
                        if((jsonData.value(forKey: "SessionStatus")) as! Int  == 2 || (jsonData.value(forKey: "SessionStatus")) as! Int == 3) {
                            //jsonData
                            let jsonObject: [String: Any] = [
                                "sessionStatus": result ,
                                "callResponse": "CallNotRespond",
                            ]
                        self.callBack?.sessionNotResponded(res: jsonObject)
                        
                        }
                        
                                    }
                    self.sessionDisconnect();
                    self.timer.invalidate()
                }
                    
            }
        }

    // MARK: -Microphone Camera and Permission Request
        func askForMicrophonePermission() {
            switch AVAudioSession.sharedInstance().recordPermission {
            case AVAudioSession.RecordPermission.granted:
                    break
                case AVAudioSession.RecordPermission.denied:
                    break
                case AVAudioSession.RecordPermission.undetermined:
                    // This is the initial state before a user has made any choice
                    // You can use this spot to request permission here if you want
                    AVAudioSession.sharedInstance().requestRecordPermission({ granted in
                        // Check for granted
                    })
                default:
                    break
            }
        }
    
    func notifyUserOfCameraAccessDenial() {
        // display a useful message asking the user to grant permissions from within Settings > Privacy > Camera
    }
    
    func sessionDisconnect() {
        changeCallStatus(callStatus: 16)
        if (session != nil)  {
            print("disconnecting....")
            session!.disconnect(nil)
            dismiss(animated: true)
        }
        dismiss(animated: true)
        onCallDisconnect?()
        durationTimer?.invalidate()
    }
    
    func requestCameraPermissionsIfNeeded() {

        // check camera authorization status
        let authStatus: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
        switch authStatus {
        case .authorized: break
                // camera authorized
                // do camera intensive stuff
            case .notDetermined:
                // request authorization

                AVCaptureDevice.requestAccess(for: .video, completionHandler: { granted in
                    DispatchQueue.main.async(execute: {

                        if granted {
                            // do camera intensive stuff
                        } else {
                            self.notifyUserOfCameraAccessDenial()
                        }
                    })
                })
            case .restricted, .denied:
                DispatchQueue.main.async(execute: {
                    self.notifyUserOfCameraAccessDenial()
                })
            default:
                break
        }
    }
    
    
    func hideVideoMuted() {
        remoteVideoMutedIndicator.isHidden = true
        localVideoMutedBg.isHidden = true
    }
   
    func setupSession() {
        //setup one time session
        if (session != nil) {
            session = nil
        }
        session = OTSession(
            apiKey: kApiKey,
            sessionId: kSessionId,
            delegate: self)
       
            var error: OTError?
            session!.connect(withToken: kToken,error: &error)
        

    }
   func connectToAnOpenTokSession() {
       session = OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)
       var error: OTError?
       session?.connect(withToken: kToken, error: &error)
       if error != nil {
           print(error!)
       }
   }
    
    func showAlert(_ string: String?) {
        // show alertview on main UI
        DispatchQueue.main.async(execute: {
            let alertVC = UIAlertController(
                title: "OTError",
                message: string,
                preferredStyle: .alert)
            self.present(alertVC, animated: true)
        })
    }
    
    
    
    
    @objc func updateTimer(){
        seconds -= 1     //This will decrement(count down)the seconds.
        print(seconds)
        if seconds == 0 {
            getSessionStatus()
            
        }
        
    }
    
}


extension VideoCallViewController: OTSessionDelegate {
    
   func sessionDidConnect(_ session: OTSession) {
        print("The client connected to the OpenTok session.")
        timer = Timer.scheduledTimer(timeInterval: 1, target: self,   selector: (#selector(VideoCallViewController.updateTimer)), userInfo: nil, repeats: true)
        setupPublisher()
    
   }
        
    func setupPublisher() {
        let settings = OTPublisherSettings()
        settings.name = UIDevice.current.name
        publisher = OTPublisher(delegate: self, settings: settings)

        var error: OTError? = nil
        session!.publish(publisher!, error: &error)
        if error != nil {
            showAlert(error?.localizedDescription)
        }
        
        publisher?.view?.tag = 11
        publisher?.view?.layer.cornerRadius = 5
        publisher?.view?.clipsToBounds = true
        smallVideoView.addSubview((publisher?.view)!)
        layoutVideoRenderViews()
    }

   func sessionDidDisconnect(_ session: OTSession) {
       print("The client disconnected from the OpenTok session.")
   }

   func session(_ session: OTSession, didFailWithError error: OTError) {
       changeCallStatus(callStatus: 16)
       print("The client failed to connect to the OpenTok session: \(error).")
   }
    
    func session(
        _ session: OTSession,
        connectionDestroyed connection: OTConnection
    ) {
       
        if subscriber?.stream!.connection.connectionId == connection.connectionId {
            cleanupSubscriber()
        }
        sessionDisconnect()
    }
    

   func session(_ session: OTSession, streamCreated stream: OTStream) {
        subscriber = OTSubscriber(stream: stream, delegate: self)
        guard let subscriber = subscriber else {
            return
        }

        var error: OTError?
        session.subscribe(subscriber, error: &error)
        guard error == nil else {
            print(error!)
            return
        }

        guard let subscriberView = subscriber.view else {
            return
        }
    subscriberView.tag = 22
    fullVideoView.addSubview(subscriberView)
    layoutVideoRenderViews()
    
    startUpdateCallDuration()
    onCallConnect?()
   }
    
    func setupSubscribe(_ stream: OTStream?) {
        subscriber = OTSubscriber(stream: stream!, delegate: self)

        var error: OTError? = nil
        session!.subscribe(subscriber!, error: &error)
        if error != nil {
            showAlert(error!.localizedDescription)
        }
    }
   func session(_ session: OTSession, streamDestroyed stream: OTStream) {
   

    if subscriber?.stream?.streamId == stream.streamId {
           cleanupSubscriber()
       }
       print("A stream was destroyed in the session.")
   }


    func cleanupSubscriber() {
        subscriber?.view!.removeFromSuperview()
        subscriber = nil
    }
    
    func session(
        _ session: OTSession?,
        connectionCreated connection: OTConnection?
    ) {
//        startTimer(callDuration, warningDuration)
        if let connectionId = connection?.connectionId {
            print("session connectionCreated (\(connectionId))")
        }
        changeCallStatus(callStatus: 3)
        isUserConnect  = true
        timer.invalidate()
    }

}

extension VideoCallViewController: OTPublisherDelegate {
   func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {
       print("The publisher failed: \(error)")
   }
}

extension VideoCallViewController: OTSubscriberDelegate {
   public func subscriberDidConnect(toStream subscriber: OTSubscriberKit) {
       print("The subscriber did connect to the stream.")
   }

   public func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {
       print("The subscriber failed to connect to the stream.")
   }
}

