//
//  QSLSocketManager.swift
//  QuickSearchLocation
//
//  Created by Destiny on 2024/12/6.
//

import SocketRocket
import Foundation

enum QSLSocketStatus: UInt {
    case connecting      // 正在连接
    case connected       // 已连接
    case failed          // 失败
    case closedByServer  // 系统关闭
    case closedByUser    // 用户关闭
    case received        // 接收消息
}

protocol QSLSocketManagerDelegate: AnyObject {
    func socketDidReceiveMessage(with string: String)
}

class QSLSocketManager: NSObject, SRWebSocketDelegate {
    
    static let shared = QSLSocketManager()
    
    private var webSocket: SRWebSocket?
    private var timer: Timer?
    private var pingTimer: Timer?  // 每10秒钟发送一次ping消息
    private var currentCount: UInt = 0  // 当前重连次数
    
    var delegate: QSLSocketManagerDelegate?
    var urlString: String = ""
    var overtime: TimeInterval = 3.0  // 重连时间间隔，默认3秒钟
    var reconnectCount: UInt = UInt.max  // 重连次数，默认无限次
    var status: QSLSocketStatus = .connecting
    
    private override init() {
        super.init()
        let url = "\(QSLApi.prodWSUrl)/websocket/\(QSLBaseManager.shared.userModel.authToken)"
        self.urlString = url
    }
    
    // MARK: - Public Methods
    
    @objc func connect() {
        // 先关闭连接
        self.webSocket?.close()
        self.webSocket?.delegate = nil
        
        // 后开启连接
        if let url = URL(string: self.urlString) {
            self.webSocket = SRWebSocket(urlRequest: URLRequest(url: url))
            self.webSocket?.delegate = self
        }
        
        self.status = .connecting
        self.webSocket?.open()
    }
    
    func close() {
        self.webSocket?.close()
        self.webSocket = nil
        self.timer?.invalidate()
        self.timer = nil
        self.pingTimer?.invalidate()
        self.pingTimer = nil
    }
    
    func reconnect() {
        guard currentCount < reconnectCount else {
            print("重连次数已用完……")
            self.timer?.invalidate()
            self.timer = nil
            return
        }
        
        // 计数器 +1
        currentCount += 1
        print("\(overtime)秒后进行第\(currentCount)次重试连接……")
        
        // 开启定时器进行重连
        self.timer = Timer.scheduledTimer(timeInterval: overtime, target: self, selector: #selector(connect), userInfo: nil, repeats: false)
        RunLoop.current.add(self.timer!, forMode: .common)
    }
    
    func sendMessage(_ message: String) {
        
        do {
            try self.webSocket?.send(string: message)
            print("消息已发送")
        } catch {
            print("发送消息失败！")
        }
    }
    
    @objc func sendPingMessage() {
        guard status == .connected else { return }
        
        do {
            try self.webSocket?.sendPing(nil)
            print("发送心跳包")
        } catch {
            print("发送心跳包失败！")
        }
    }
    
    // MARK: - SRWebSocketDelegate Methods
    
    func webSocket(_ webSocket: SRWebSocket, didReceiveMessageWith string: String) {
        delegate?.socketDidReceiveMessage(with: string)
        
        let locationMessage = QSLMapMessageModel.mapModel(from: string)
        switch locationMessage.cmd {
        case "d.refresh.friend.list":
            NotificationCenter.default.post(name: QSLNotification.QSLRefreshFriend, object: nil)
            break
        case "d.refresh.friend.message":
            NotificationCenter.default.post(name: QSLNotification.QSLRefreshMessage, object: nil)
            break
        case "d.refresh.friend.request":
            NotificationCenter.default.post(name: QSLNotification.QSLRefreshRequest, object: nil)
            break
        case "d.refresh.contact":
            NotificationCenter.default.post(name: QSLNotification.QSLRefreshContact, object: nil)
            break
        case "d.refresh.member":
            NotificationCenter.default.post(name: QSLNotification.QSLRefreshMember, object: nil)
            break
        default:
            break
        }
        print("收到信息：\(string)")
    }
    
    func webSocketDidOpen(_ webSocket: SRWebSocket) {
        print("已链接服务器：\(webSocket.url ?? URL(fileURLWithPath: ""))")
        
        // 重置计数器
        self.currentCount = 0
        self.status = .connected
        
        // 开启ping定时器
        self.pingTimer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(sendPingMessage), userInfo: nil, repeats: true)
        RunLoop.current.add(self.pingTimer!, forMode: .common)
    }
    
    func webSocket(_ webSocket: SRWebSocket, didFailWithError error: Error) {
        print("链接失败：\(error.localizedDescription)")
        
        self.status = .failed
        
        // 尝试重新连接
        reconnect()
    }
    
    func webSocket(_ webSocket: SRWebSocket, didCloseWithCode code: Int, reason: String?, wasClean: Bool) {
        print("链接已关闭：code:\(code)   reason:\(String(describing: reason))")
        
        if code == 1000 {
            self.status = .closedByUser
        } else {
            self.status = .closedByServer
            reconnect()
        }
    }
    
    func webSocket(_ webSocket: SRWebSocket, didReceivePingWith data: Data?) {
        print("收到 Ping")
    }
    
    func webSocket(_ webSocket: SRWebSocket, didReceivePong pongData: Data?) {
        print("收到 Pong")
    }
}
