//
//  PhoneCallViewModel.swift

//
//  Created by Leon on 2025/8/27.
//

import Foundation
import BytePlusRTC
import AVFoundation

enum PhoneCallOptType: String {
    case START
    case INTERRUPT
    case STOP
}

protocol PhoneCallViewModelDelegate: AnyObject{
    func phoneCallLocalUserSaying(saying: Bool)
}

class PhoneCallViewModel: NSObject {
    weak var delegate: PhoneCallViewModelDelegate?
    
    /// text, userId(String type)
    var subTitleCallbck: ((String, String)-> Void)?
    
    private(set) var token: String?
    
    var aiId : Int?{
        didSet{
            roomId = "\(UserCore.shared.user?.userId ?? 0)-\(aiId ?? 0)"
        }
    }
    var roomId : String?
    
    private(set) var rtcVideo: ByteRTCVideo?
    private(set) var rtcRoom: ByteRTCRoom?
    
    // 字幕相关
    var aiCompleteMessage = [String]()
    /// 强制离开房间
    var leaveTheRoomForcedAction : (()->Void)?
    
    func loadRtc(completion: ((Bool)-> Void)?) {
        guard let rtcRoomId = roomId else {return}
        AICowProvider.request(.voiceAICallRtcToken(roomId: rtcRoomId), modelType: PhoneCallRtcGetResponse.self) { [weak self] result in
            switch result {
            case let .success(model):
                self?.token = model?.token
                self?.buildRTCEngine()
                self?.joinRoom()
                completion?(true)
            case .failure:
                completion?(false)
            }
        }
    }

    func opt(type: PhoneCallOptType, timestamp:Int, duration: Int = 0, completion:((Bool)->Void)?){
        guard let rtcRoomId = roomId, let aiUid = aiId else{return}
        
        let taskId = "\(rtcRoomId)-\(timestamp)"
        
        var params = [String:Any]()
        params.updateValue(aiUid, forKey: "aiId")
        params.updateValue(rtcRoomId, forKey: "roomId")
        params.updateValue(taskId, forKey: "taskId")
        params.updateValue(type.rawValue, forKey: "optType")
        
        if duration > 0{
            params.updateValue(duration, forKey: "duration")
        }
        
        AICowProvider.request(.voiceCallOperate(params: params), modelType: EmptyModel.self) {[weak self] result in
            switch result {
            case .success:
                completion?(true)
            case .failure(let failure):
                switch failure {
                case let .serviceError(code, _):
                    if code == .insufficentCoin{
                        // 离开rtc
                        self?.leaveRoom()
                        // 离开打电话
                        self?.leaveTheRoomForcedAction?()
                    }
                default:
                    break
                }
                completion?(false)
                break
            }
        }
    }
    deinit {
        destoryBytePlus()
    }
    
}

extension PhoneCallViewModel{
    public func leaveRoom(){
        self.rtcVideo?.logout()
        self.rtcRoom?.leaveRoom()
    }
    
    private func destoryBytePlus() {
        self.rtcRoom?.destroy()
        ByteRTCVideo.destroyRTCVideo();
        self.rtcVideo = nil
        self.rtcRoom = nil
    }
    
    private func buildRTCEngine() {
        /// Create engine objects.
        self.rtcVideo = ByteRTCVideo.createRTCVideo("689ade491323ae01797818e0", delegate: self, parameters: [:])
        
        /// Start pushing multiple video streams and set the video parameters when pushing multiple streams,
        /// Including resolution, frame rate, bit rate, zoom mode, fallback strategy when the network is poor, etc.
        
        let encoderCfg = ByteRTCVideoEncoderConfig.init()
        encoderCfg.width = 360
        encoderCfg.height = 640
        encoderCfg.frameRate = 15
        encoderCfg.maxBitrate = 800
        self.rtcVideo?.setMaxVideoEncoderConfig(encoderCfg)
        
        /// Enable internal video capture immediately. The default is off.
        // self.rtcVideo?.startVideoCapture()
        
        // 开启音量上报
        let audioPropertiesConfig = ByteRTCAudioPropertiesConfig()
        audioPropertiesConfig.interval = 200
        self.rtcVideo?.enableAudioPropertiesReport(audioPropertiesConfig)
        
        /// Enables internal audio capture. The default is off.
        self.rtcVideo?.startAudioCapture()
    }
    
    private func joinRoom() {
        guard let rtcRoomId = roomId, let roomToken = token else{
            return
        }
        // joinroom
        self.rtcRoom = self.rtcVideo?.createRTCRoom(rtcRoomId)
        self.rtcRoom?.delegate = self
        let userInfo = ByteRTCUserInfo.init()
        userInfo.userId = "\(UserCore.shared.user?.userId ?? 0)"
        let roomCfg = ByteRTCRoomConfig.init()
        roomCfg.isAutoPublish = true
        roomCfg.isAutoSubscribeAudio = true
        //roomCfg.isAutoSubscribeVideo = true
        self.rtcRoom?.joinRoom(roomToken, userInfo: userInfo, roomConfig: roomCfg)
        self.rtcRoom?.publishStream(.audio) // self.rtcRoom?.unpublishStream(.audio)
    }
    
    
    
}

extension PhoneCallViewModel: ByteRTCRoomDelegate{
    func rtcRoom(_ rtcRoom: ByteRTCRoom, onUserJoined userInfo: ByteRTCUserInfo, elapsed: Int) {
        dlog("☎️user joined: \(userInfo)")
    }
    
    func rtcRoom(_ rtcRoom: ByteRTCRoom, onUserLeave uid: String, reason: ByteRTCUserOfflineReason) {
        dlog("☎️user leaved: uid:\(uid), reason: \(reason)")
    }
    
    func rtcEngine(_ engine: ByteRTCVideo, onError errorCode: ByteRTCErrorCode) {
        NSLog("☎️onError: %zd", errorCode.rawValue)
    }
    
    func rtcEngine(_ engine: ByteRTCVideo, onWarning Code: ByteRTCWarningCode) {
        NSLog("☎️onWarning: %zd", Code.rawValue)
    }
}

extension PhoneCallViewModel: ByteRTCVideoDelegate{
//    func rtcEngine(_ engine: ByteRTCVideo, onActiveSpeaker roomId: String, uid: String) { // 此方法不会回调
//        print("roomId: \(roomId), uid is speaking:\(uid)")
//    }
    
    func rtcRoom(_ rtcRoom: ByteRTCRoom, onRoomBinaryMessageReceived uid: String, message: Data) {
        let subtitles = SubtitleParser.parse(from: message)
        for sub in subtitles {
            DispatchQueue.main.async {[weak self] in
                if "\(UserCore.shared.user?.userId ?? 0)" == sub.userId{
                    print("用户字幕: \(sub.text), 用户: \(sub.userId), 时间戳: \(sub.timestamp ?? 0)")
                    // 表示是我自己在说话，清空所有暂存的ai说的话。
                    self?.aiCompleteMessage.removeAll()
                    self?.subTitleCallbck?(sub.text, sub.userId)
                }else{
                    print("AI字幕: \(sub.text), AI: \(sub.userId), 时间戳: \(sub.timestamp ?? 0)")
                    // AI在说话
                    self?.handleAISubtitle(sub)
                }
            }
        }
        
        /*
         {
           "data": [
             {
               "definite": true,
               "language": "zh",
               "mode": 0,
               "paragraph": true,
               "roundId": 0,
               "sequence": 15,
               "text": "你好啊，我是小爱同学，很高兴认识你。",
               "timestamp": 1756273528308,
               "userId": "439217670979585"
             }
           ],
           "type": "subtitle"
         }
         */
        
//        if let jsonString = SubtitleParser.parseRawJSON(from: message) {
//            print("👉 解包后JSON: \(jsonString)")
//        }
    }
    
    /// 处理AI字幕的拼接逻辑
    private func handleAISubtitle(_ sub: SubtitleMsgData) {
        // 判断一句话是否说完
        let isComplete = sub.paragraph || sub.definite
        
        if isComplete {
            // 情况1: paragraph为true 或 情况2: paragraph为false但definite为true
            // 将完整的text添加到aiCompleteMessage中
            aiCompleteMessage.append(sub.text)
            // 显示拼接后的完整字幕
            let completeSubtitle = aiCompleteMessage.joined(separator: "\n")
            subTitleCallbck?(completeSubtitle, sub.userId)
        } else {
            // paragraph和definite都为false，表示这句话还没说完
            // 显示暂存字幕 + 当前更新的text
            let currentSubtitle = aiCompleteMessage.joined(separator: "\n") + (aiCompleteMessage.isEmpty ? "" : "\n") + sub.text
            subTitleCallbck?(currentSubtitle, sub.userId)
        }
    }
    
    func rtcRoom(_ rtcRoom: ByteRTCRoom, onRoomStateChanged roomId: String, withUid uid: String, state: Int, extraInfo: String) {
        NSLog("☎️onRoomStateChanged uid:\(uid), extraInfo:\(extraInfo)")
    }
}

extension PhoneCallViewModel{
    func rtcEngine(_ engine: ByteRTCVideo, onLocalAudioPropertiesReport audioPropertiesInfos: [ByteRTCLocalAudioPropertiesInfo]) {
        var imSaying = false
        for info in audioPropertiesInfos {
            if info.audioPropertiesInfo.linearVolume > 25{ // 表示我在说话
                imSaying = true
                break
            }
        }
        
        delegate?.phoneCallLocalUserSaying(saying: imSaying)
    }
}

// MARK: - Helper字幕解析
// 对应字幕数据结构
struct SubtitleMsgData: Codable {
    let definite: Bool
    let language: String
    let paragraph: Bool
    let sequence: Int
    let text: String
    let userId: String
    
    // 新增的可选字段
    let mode: Int?
    let roundId: Int?
    let timestamp: Int?
}

// 根结构
struct SubtitleRoot: Codable {
    let data: [SubtitleMsgData]
    let type: String
}

enum SubtitleParser {
    private static let kSubtitleHeaderSize = 8
    private static let magicNumber: UInt32 = 0x73756276
    
    private static func unpackMessage(_ message: Data) -> String? {
        guard message.count >= kSubtitleHeaderSize else { return nil }
        
        // 读取 magic number
        let magic = message.prefix(4).reduce(0) { ($0 << 8) | UInt32($1) }
        guard magic == magicNumber else { return nil }
        
        // 长度
        let length = message.dropFirst(4).prefix(4).reduce(0) { ($0 << 8) | UInt32($1) }
        guard message.count - kSubtitleHeaderSize == length else { return nil }
        
        // JSON 字符串
        let jsonData = message.dropFirst(kSubtitleHeaderSize)
        return String(data: jsonData, encoding: .utf8)
    }
    
    /// 最终解析方法，返回 `[SubtitleMsgData]`
    static func parse(from message: Data) -> [SubtitleMsgData] {
        guard let jsonString = unpackMessage(message),
              let jsonData = jsonString.data(using: .utf8) else {
            return []
        }
        
        do {
            let root = try JSONDecoder().decode(SubtitleRoot.self, from: jsonData)
            return root.data
        } catch {
            print("Subtitle JSON parse error: \(error)")
            return []
        }
    }
    
    /// 调试用：返回解包后的 JSON
    static func parseRawJSON(from message: Data) -> String? {
        return unpackMessage(message)
    }
}
// MARK: - Other
class PhoneCallRtcGetResponse: Codable {
    var token: String?
}
