//
//  ProviderDelegate.swift
//  CallTutorial
//
//  Created by QuentinArguillere on 05/08/2020.
//  Copyright © 2020 BelledonneCommunications. All rights reserved.
//

import Foundation
import CallKit
import linphonesw
import AVFoundation


class CallKitProviderDelegate : NSObject
{
	private let provider: CXProvider
	let mCallController = CXCallController()
	var tutorialContext : CallKitExampleContext!
	
	var incomingCallUUID : UUID!
	
	init(context: CallKitExampleContext)
	{
		tutorialContext = context
		let providerConfiguration = CXProviderConfiguration()
		providerConfiguration.supportsVideo = true
		providerConfiguration.supportedHandleTypes = [.generic]
		
		providerConfiguration.maximumCallsPerCallGroup = 1
		providerConfiguration.maximumCallGroups = 1
		
		provider = CXProvider(configuration: providerConfiguration)
		super.init()
		provider.setDelegate(self, queue: nil) // The CXProvider delegate will trigger CallKit related callbacks
		
	}
	
	func incomingCall()
	{
		NSLog("Callkit  incomingCall -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ")
		incomingCallUUID = UUID()
		let update = CXCallUpdate()
		update.remoteHandle = CXHandle(type:.generic, value: tutorialContext.incomingCallName)
		
		provider.reportNewIncomingCall(with: incomingCallUUID, update: update, completion: { error in }) // Report to CallKit a call is incoming
	}
	
	func stopCall()
	{
		NSLog("Callkit  stopCall -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ")
		let endCallAction = CXEndCallAction(call: incomingCallUUID)
		let transaction = CXTransaction(action: endCallAction)
		
		mCallController.request(transaction, completion: { error in }) // Report to CallKit a call must end
	}
	
}


// In this extension, we implement the action we want to be done when CallKit is notified of something.
// This can happen through the CallKit GUI in the app, or directly in the code (see, incomingCall(), stopCall() functions above)
extension CallKitProviderDelegate: CXProviderDelegate {
	
	func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
		NSLog("Callkit  CXEndCallAction -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ")
		do {
			if (tutorialContext.mCall?.state != .End && tutorialContext.mCall?.state != .Released)  {
				try tutorialContext.mCall?.terminate()
			}
		} catch { NSLog(error.localizedDescription) }
		
		tutorialContext.isCallRunning = false
		tutorialContext.isCallIncoming = false
		action.fulfill()
	}
	
	func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
		NSLog("Callkit  CXAnswerCallAction -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ")
		do {
			// The audio stream is going to start shortly: the AVAudioSession must be configured now.
			// It is worth to note that an application does not have permission to configure the
			// AVAudioSession outside of this delegate action while it is running in background,
			// which is usually the case in an incoming call scenario.
			tutorialContext.mCore.configureAudioSession();
			try tutorialContext.mCall?.accept()
			tutorialContext.isCallRunning = true
		} catch {
			print(error)
		}
		action.fulfill()
	}
	
	func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {}
	func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
		// This tutorial is not doing outgoing calls. If it had to do so,
		// configureAudioSession() shall be called from here, just before launching the
		// call.
		// tutorialContext.mCore.configureAudioSession();
		// tutorialContext.mCore.invite("sip:bob@example.net");
		// action.fulfill();
	}
	func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {}
	func provider(_ provider: CXProvider, perform action: CXPlayDTMFCallAction) {}
	func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {}
	func providerDidReset(_ provider: CXProvider) {}
	
	func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
		NSLog("Callkit  didActivateaudiosession -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ")
		// The linphone Core must be notified that CallKit has activated the AVAudioSession
		// in order to start streaming audio.
		tutorialContext.linphoneAsyncHelper.postOnCoreQueue {
			self.tutorialContext.mCore.activateAudioSession(actived: true)
		}
	}
	
	func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
		// The linphone Core must be notified that CallKit has deactivated the AVAudioSession.
		tutorialContext.linphoneAsyncHelper.postOnCoreQueue {
			self.tutorialContext.mCore.activateAudioSession(actived: false)
		}
	}
}