import Foundation

protocol SignalingClientDelegate: AnyObject {
    func signalingDidConnect()
    func signalingDidDisconnect()
    func signaling(didFail error: String)
    func signaling(didReceive message: SignalMessage)
}

/// 信令 WebSocket 客户端（URLSessionWebSocketTask 实现）。
/// 连接成功后自动发送 REGISTER（deviceType = CONTROLLER），
/// 所有回调均已切换到主线程。
final class SignalingClient: NSObject {

    weak var delegate: SignalingClientDelegate?

    private let serverUrl: String
    private let deviceId: String
    private var session: URLSession?
    private var task: URLSessionWebSocketTask?
    private var manuallyClosed = false

    init(serverUrl: String, deviceId: String) {
        self.serverUrl = serverUrl
        self.deviceId = deviceId
        super.init()
    }

    func connect() {
        guard let url = URL(string: serverUrl) else {
            notifyError("无效的服务器地址: \(serverUrl)")
            return
        }
        manuallyClosed = false
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForRequest = 15
        session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
        task = session?.webSocketTask(with: url)
        task?.resume()
        receiveLoop()
    }

    func disconnect() {
        manuallyClosed = true
        task?.cancel(with: .normalClosure, reason: "Disconnecting".data(using: .utf8))
        task = nil
        session?.invalidateAndCancel()
        session = nil
    }

    func send(_ message: SignalMessage) {
        guard let task else { return }
        guard let data = try? JSONEncoder().encode(message),
              let json = String(data: data, encoding: .utf8) else { return }
        task.send(.string(json)) { error in
            if let error {
                NSLog("[Signaling] send error: \(error.localizedDescription)")
            }
        }
    }

    var isConnected: Bool { task != nil }

    // MARK: - Private

    private func registerDevice() {
        var msg = SignalMessage()
        msg.type = "REGISTER"
        msg.fromDeviceId = deviceId
        msg.deviceType = "CONTROLLER"
        send(msg)
    }

    private func receiveLoop() {
        task?.receive { [weak self] result in
            guard let self else { return }
            switch result {
            case .success(let wsMessage):
                if case .string(let text) = wsMessage,
                   let data = text.data(using: .utf8),
                   let message = try? JSONDecoder().decode(SignalMessage.self, from: data) {
                    DispatchQueue.main.async {
                        self.delegate?.signaling(didReceive: message)
                    }
                }
                self.receiveLoop()
            case .failure(let error):
                if !self.manuallyClosed {
                    self.notifyError(error.localizedDescription)
                }
            }
        }
    }

    private func notifyError(_ text: String) {
        DispatchQueue.main.async {
            self.delegate?.signaling(didFail: text)
        }
    }
}

// MARK: - URLSessionWebSocketDelegate

extension SignalingClient: URLSessionWebSocketDelegate {

    func urlSession(_ session: URLSession,
                    webSocketTask: URLSessionWebSocketTask,
                    didOpenWithProtocol protocol: String?) {
        registerDevice()
        DispatchQueue.main.async {
            self.delegate?.signalingDidConnect()
        }
    }

    func urlSession(_ session: URLSession,
                    webSocketTask: URLSessionWebSocketTask,
                    didCloseWith closeCode: URLSessionWebSocketTask.CloseCode,
                    reason: Data?) {
        guard !manuallyClosed else { return }
        DispatchQueue.main.async {
            self.delegate?.signalingDidDisconnect()
        }
    }
}
