//
//  Agora.swift
//  SodaLive
//
//  Created by klaus on 2023/08/14.
//

import Foundation
import AgoraRtcKit
import AgoraRtmKit

final class Agora {
    static let shared = Agora()
    
    var rtcEngineDelegate: AgoraRtcEngineDelegate?
    var rtmDelegate: AgoraRtmDelegate?
    
    var rtcEngine: AgoraRtcEngineKit?
    
    var rtmKit: AgoraRtmKit?
    var rtmChannel: AgoraRtmChannel?
    
    func initialize() {
        rtcEngine = AgoraRtcEngineKit.sharedEngine(withAppId: AGORA_APP_ID, delegate: rtcEngineDelegate)
        rtcEngine?.setChannelProfile(.liveBroadcasting)
        rtcEngine?.enableAudio()
        rtcEngine?.enableAudioVolumeIndication(500, smooth: 3, reportVad: true)
        
        rtmKit = AgoraRtmKit(appId: AGORA_APP_ID, delegate: rtmDelegate)
    }
    
    func deInit() {
        if let rtcEngine = rtcEngine {
            rtcEngine.leaveChannel(nil)
            
            DispatchQueue.global(qos: .userInitiated).async {
                AgoraRtcEngineKit.destroy()
            }
        }
        
        rtmChannel?.leave(completion: nil)
        rtmKit?.logout(completion: nil)
        rtcEngine = nil
        rtmChannel = nil
        rtmKit = nil
    }
    
    func setRole(role: AgoraClientRole) {
        self.rtcEngine?.setClientRole(role)
    }
    
    func joinChannel(
        roomInfo: GetRoomInfoResponse,
        rtmChannelDelegate: AgoraRtmChannelDelegate,
        onConnectSuccess: @escaping (Bool) -> Void,
        onConnectFail: @escaping () -> Void
    ) {
        if rtmChannel != nil {
            return
        }
        
        let userId = UserDefaults.int(forKey: .userId)
        
        rtcEngine?.joinChannel(
            byToken: roomInfo.rtcToken,
            channelId: roomInfo.channelName,
            info: nil,
            uid: UInt(userId),
            joinSuccess: nil
        )
        
        rtcEngine?.setAudioProfile(.musicHighQualityStereo)
        rtcEngine?.setAudioScenario(.gameStreaming)
        
        rtmChannel = rtmKit?.createChannel(
            withId: roomInfo.channelName,
            delegate: rtmChannelDelegate
        )
        
        rtmKit?.login(
            byToken: roomInfo.rtmToken,
            user: String(userId),
            completion: { [unowned self] loginErrorCode in
                if loginErrorCode == .ok {
                    self.rtmChannel?.join(completion: { joinChannelErrorCode in
                        if joinChannelErrorCode == .channelErrorOk {
                            if userId == roomInfo.creatorId {
                                self.setRole(role: .broadcaster)
                            } else {
                                self.setRole(role: .audience)
                            }
                            
                            onConnectSuccess(userId == roomInfo.creatorId)
                        } else {
                            onConnectFail()
                        }
                    })
                } else {
                    onConnectFail()
                }
            }
        )
    }
    
    func sendMessageToPeer(peerId: String, rawMessage: Data, completion: AgoraRtmSendPeerMessageBlock?) {
        let option = AgoraRtmSendMessageOptions()
        option.enableOfflineMessaging = false
        option.enableHistoricalMessaging = false
        
        let message = AgoraRtmRawMessage(rawData: rawMessage, description: "")
        rtmKit?.send(message, toPeer: peerId, completion: completion)
    }
    
    func sendRawMessageToPeer(peerId: String, rawMessage: LiveRoomChatRawMessage, completion: AgoraRtmSendPeerMessageBlock? = nil, fail: (() -> Void)? = nil) {
        let encoder = JSONEncoder()
        let jsonMessageData = try? encoder.encode(rawMessage)
        let option = AgoraRtmSendMessageOptions()
        option.enableOfflineMessaging = false
        option.enableHistoricalMessaging = false
        
        if let jsonMessageData = jsonMessageData {
            let message = AgoraRtmRawMessage(rawData: jsonMessageData, description: "")
            rtmKit?.send(message, toPeer: peerId, sendMessageOptions: option, completion: completion)
        } else {
            if let fail = fail {
                fail()
            }
        }
    }
    
    func mute(_ isMute: Bool) {
        rtcEngine?.muteLocalAudioStream(isMute)
    }
    
    func speakerMute(_ isMute: Bool) {
        rtcEngine?.muteAllRemoteAudioStreams(isMute)
    }
    
    func sendMessageToGroup(textMessage: String, completion: @escaping AgoraRtmSendChannelMessageBlock) {
        let message = AgoraRtmMessage(text: textMessage)
        rtmChannel?.send(message, completion: completion)
    }
    
    func sendRawMessageToGroup(rawMessage: LiveRoomChatRawMessage, completion: AgoraRtmSendChannelMessageBlock? = nil, fail: (() -> Void)? = nil) {
        let encoder = JSONEncoder()
        let jsonMessageData = try? encoder.encode(rawMessage)
        
        if let jsonMessageData = jsonMessageData {
            let message = AgoraRtmRawMessage(rawData: jsonMessageData, description: "")
            rtmChannel?.send(message, completion: completion)
        } else {
            if let fail = fail {
                fail()
            }
        }
    }
}