import Foundation
import Combine
import UIKit
import WebRTC

/// 鉴权方式（与被控端约定一致）
enum AuthType: String, CaseIterable, Identifiable {
    case none = "NONE"
    case code = "CODE"
    case password = "PASSWORD"

    var id: String { rawValue }

    var title: String {
        switch self {
        case .none: return "免密连接"
        case .code: return "动态验证码"
        case .password: return "固定密码"
        }
    }
}

/// 串流模式
enum StreamMode: Int {
    case webrtc = 0
    case selfCodec = 1
}

/// 分辨率档位（与 Android 端一致，0 表示原始画质）
struct ResolutionOption: Identifiable, Equatable {
    let id: Int
    let title: String
    let width: Int32
    let height: Int32

    static let all: [ResolutionOption] = [
        ResolutionOption(id: 0, title: "原始画质", width: 0, height: 0),
        ResolutionOption(id: 1, title: "1080P", width: 1920, height: 1080),
        ResolutionOption(id: 2, title: "720P", width: 1280, height: 720),
        ResolutionOption(id: 3, title: "480P", width: 854, height: 480)
    ]
}

/// 主控端 ViewModel：串联信令、WebRTC、自编码解码与 UI 状态。
/// 所有回调均已在主线程触发，@Published 属性直接驱动 SwiftUI。
final class ControllerViewModel: NSObject, ObservableObject {

    // MARK: - UI 状态

    @Published var serverUrl: String = "wss://www.ttstd.com/signal"
    @Published var targetDeviceId: String = ""
    @Published var statusText: String = "未连接"
    /// 是否显示控制界面（对应 Android 的 setupPanel/controlPanel 切换）
    @Published var isControlling: Bool = false
    @Published var isConnecting: Bool = false
    @Published var statsText: String = ""
    @Published var streamMode: StreamMode = .webrtc
    @Published var selectedResolution: ResolutionOption = ResolutionOption.all[0]
    /// 帧率档位：默认常用档位，收到被控端上报的 supported_fps 后以上报列表为准
    @Published var fpsOptions: [Int] = [15, 24, 30, 60]
    /// 被控端当前采集帧率（0 表示尚未收到上报）
    @Published var currentFps: Int = 0
    /// 远端视频宽高比（宽/高），用于让触控层与画面精确对齐
    @Published var videoAspect: CGFloat = 9.0 / 16.0
    @Published var showAuthSheet: Bool = false
    @Published var alertMessage: String?

    let myDeviceId: String = DeviceUtils.deviceId()

    // MARK: - UIKit 渲染视图（由 ViewModel 持有，SwiftUI 通过 Representable 嵌入）

    let remoteVideoView = RTCMTLVideoView()
    let selfCodecView = SampleBufferDisplayView()

    // MARK: - 内部组件

    private var signalingClient: SignalingClient?
    private var webRTCClient: WebRTCClient?
    private let selfCodecDecoder = SelfCodecDecoder()

    private var statsTimer: Timer?
    private var connectionStartTime: Date?
    private var lastBytesReceived: Double = 0
    private var lastStatsTime: Date?
    private var pendingAuthType: AuthType = .none
    private var pendingAuthValue: String = ""
    /// 是否为本端主动切换串流模式（避免上报回环再次发送）
    private var suppressStreamModeSend = false
    /// 被控端最近上报的实际采集尺寸（仅切帧率时保持分辨率不变，0 表示原生）
    private var lastReportedWidth: Int32 = 0
    private var lastReportedHeight: Int32 = 0

    override init() {
        super.init()
        remoteVideoView.delegate = self
        selfCodecDecoder.displayLayer = selfCodecView.sampleBufferLayer
        selfCodecDecoder.onResolutionUpdate = { [weak self] w, h in
            guard let self, self.streamMode == .selfCodec, w > 0, h > 0 else { return }
            self.videoAspect = CGFloat(w) / CGFloat(h)
        }
    }

    // MARK: - 连接 / 断开

    /// 用户点击"连接"：弹出鉴权选择
    func requestConnect() {
        let target = targetDeviceId.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !serverUrl.trimmingCharacters(in: .whitespaces).isEmpty else {
            alertMessage = "请输入信令服务器地址"
            return
        }
        guard !target.isEmpty else {
            alertMessage = "请输入目标设备 ID"
            return
        }
        showAuthSheet = true
    }

    /// 鉴权弹窗确认后开始连接
    func connect(authType: AuthType, authValue: String) {
        showAuthSheet = false
        pendingAuthType = authType
        pendingAuthValue = authValue
        isConnecting = true
        statusText = "正在连接信令服务器..."

        let signaling = SignalingClient(
            serverUrl: serverUrl.trimmingCharacters(in: .whitespaces),
            deviceId: myDeviceId)
        signaling.delegate = self
        signalingClient = signaling
        signaling.connect()
    }

    func disconnect() {
        stopStatsTimer()
        selfCodecDecoder.setEnabled(false)
        webRTCClient?.close()
        webRTCClient = nil
        signalingClient?.disconnect()
        signalingClient = nil
        isConnecting = false
        isControlling = false
        statusText = "未连接"
        statsText = ""
        streamMode = .webrtc
        selectedResolution = ResolutionOption.all[0]
        fpsOptions = [15, 24, 30, 60]
        currentFps = 0
        lastReportedWidth = 0
        lastReportedHeight = 0
        videoAspect = 9.0 / 16.0
    }

    // MARK: - 远程输入

    func sendMotionEvent(action: Int32, x: Double, y: Double) {
        var msg = ControlMessage()
        msg.action = .motionEvent
        msg.motionAction = action
        msg.x = x
        msg.y = y
        webRTCClient?.sendControlCommand(msg)
    }

    func sendSwipe(x1: Double, y1: Double, x2: Double, y2: Double, duration: Int64) {
        var msg = ControlMessage()
        msg.action = .swipe
        msg.x1 = x1
        msg.y1 = y1
        msg.x2 = x2
        msg.y2 = y2
        msg.duration = duration
        webRTCClient?.sendControlCommand(msg)
    }

    /// 发送按键（Android KeyEvent keyCode），完整的按下+抬起
    func sendKey(_ keyCode: Int32) {
        var down = ControlMessage()
        down.action = .key
        down.keyCode = keyCode
        down.keyAction = 0
        webRTCClient?.sendControlCommand(down)

        var up = ControlMessage()
        up.action = .key
        up.keyCode = keyCode
        up.keyAction = 1
        webRTCClient?.sendControlCommand(up)
    }

    /// Android 按键常量
    enum AndroidKey {
        static let back: Int32 = 4
        static let home: Int32 = 3
        static let appSwitch: Int32 = 187
    }

    // MARK: - 分辨率 / 串流模式

    func selectResolution(_ option: ResolutionOption) {
        selectedResolution = option
        webRTCClient?.requestResolutionChange(width: option.width, height: option.height, fps: 0)
    }

    /// 仅切换帧率：分辨率沿用被控端最近上报的实际采集尺寸（0 表示原生）
    func selectFps(_ fps: Int) {
        guard fps > 0, fps != currentFps else { return }
        webRTCClient?.requestResolutionChange(width: lastReportedWidth,
                                              height: lastReportedHeight,
                                              fps: Int32(fps))
    }

    func toggleStreamMode(_ selfCodecOn: Bool) {
        let newMode: StreamMode = selfCodecOn ? .selfCodec : .webrtc
        guard newMode != streamMode else { return }
        streamMode = newMode
        applyStreamModeLocally(newMode)
        if !suppressStreamModeSend {
            webRTCClient?.sendStreamMode(Int32(newMode.rawValue))
        }
    }

    private func applyStreamModeLocally(_ mode: StreamMode) {
        selfCodecDecoder.setEnabled(mode == .selfCodec)
    }

    // MARK: - 私有

    fileprivate func startWebRTC() {
        guard let signaling = signalingClient else { return }
        statusText = "正在建立 WebRTC 连接..."
        let client = WebRTCClient(signaling: signaling, myDeviceId: myDeviceId)
        client.delegate = self
        client.selfCodecDecoder = selfCodecDecoder
        webRTCClient = client
        client.createOffer(
            targetDeviceId: targetDeviceId.trimmingCharacters(in: .whitespacesAndNewlines),
            renderer: remoteVideoView,
            authType: pendingAuthType.rawValue,
            authValue: pendingAuthType == .none ? nil : pendingAuthValue)
    }

    fileprivate func failConnection(_ reason: String) {
        alertMessage = reason
        disconnect()
    }

    // MARK: - 统计

    private func startStatsTimer() {
        connectionStartTime = Date()
        lastBytesReceived = 0
        lastStatsTime = nil
        statsTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.collectStats()
        }
    }

    private func stopStatsTimer() {
        statsTimer?.invalidate()
        statsTimer = nil
    }

    private func collectStats() {
        webRTCClient?.stats { [weak self] report in
            guard let self else { return }
            let text = self.buildStatsText(report)
            DispatchQueue.main.async {
                self.statsText = text
            }
        }
    }

    private func buildStatsText(_ report: RTCStatisticsReport) -> String {
        var width = 0, height = 0
        var fps: Double = 0
        var bytesReceived: Double = 0
        var framesDropped: Double = 0
        var codecId: String?
        var codecName = ""
        var decoderImpl = ""
        var rttMs: Double = -1
        var localCandidateId: String?
        var remoteCandidateId: String?

        for (_, stat) in report.statistics {
            switch stat.type {
            case "inbound-rtp":
                guard (stat.values["kind"] as? String) == "video" else { continue }
                width = (stat.values["frameWidth"] as? NSNumber)?.intValue ?? width
                height = (stat.values["frameHeight"] as? NSNumber)?.intValue ?? height
                fps = (stat.values["framesPerSecond"] as? NSNumber)?.doubleValue ?? fps
                bytesReceived = (stat.values["bytesReceived"] as? NSNumber)?.doubleValue ?? bytesReceived
                framesDropped = (stat.values["framesDropped"] as? NSNumber)?.doubleValue ?? framesDropped
                codecId = stat.values["codecId"] as? String
                decoderImpl = (stat.values["decoderImplementation"] as? String) ?? decoderImpl
            case "candidate-pair":
                let nominated = (stat.values["nominated"] as? NSNumber)?.boolValue ?? false
                let state = stat.values["state"] as? String
                if nominated && state == "succeeded" {
                    rttMs = ((stat.values["currentRoundTripTime"] as? NSNumber)?.doubleValue ?? 0) * 1000
                    localCandidateId = stat.values["localCandidateId"] as? String
                    remoteCandidateId = stat.values["remoteCandidateId"] as? String
                }
            default:
                break
            }
        }

        if let codecId, let codecStat = report.statistics[codecId] {
            codecName = (codecStat.values["mimeType"] as? String)?
                .replacingOccurrences(of: "video/", with: "") ?? ""
        }

        // 码率（与 Android 一致：按字节增量/时间差计算）
        var bitrateText = "--"
        let now = Date()
        if let last = lastStatsTime, bytesReceived >= lastBytesReceived {
            let interval = now.timeIntervalSince(last)
            if interval > 0 {
                let bps = (bytesReceived - lastBytesReceived) * 8 / interval
                bitrateText = Self.formatBitrate(bps)
            }
        }
        lastBytesReceived = bytesReceived
        lastStatsTime = now

        // 连接类型
        var connType = "--"
        if let lid = localCandidateId, let rid = remoteCandidateId,
           let local = report.statistics[lid], let remote = report.statistics[rid] {
            let localType = (local.values["candidateType"] as? String) ?? ""
            let remoteType = (remote.values["candidateType"] as? String) ?? ""
            let proto = ((local.values["protocol"] as? String) ?? "").uppercased()
            if localType == "relay" || remoteType == "relay" {
                connType = "TURN 中继(\(proto))"
            } else if localType == "srflx" || remoteType == "srflx" {
                connType = "P2P 公网直连(\(proto))"
            } else if localType == "host" && remoteType == "host" {
                connType = "P2P 局域网直连(\(proto))"
            } else {
                connType = "\(localType)/\(remoteType)(\(proto))"
            }
        }

        var duration = ""
        if let start = connectionStartTime {
            let secs = Int(Date().timeIntervalSince(start))
            duration = String(format: "%02d:%02d", secs / 60, secs % 60)
        }

        let modeText = streamMode == .selfCodec ? "自编码" : "WebRTC"
        var lines: [String] = []
        lines.append("模式: \(modeText)  时长: \(duration)")
        if streamMode == .selfCodec {
            let w = selfCodecDecoder.videoWidth
            let h = selfCodecDecoder.videoHeight
            lines.append("分辨率: \(w > 0 ? "\(w)x\(h)" : "--")  解码: VideoToolbox(H264)")
        } else {
            lines.append("分辨率: \(width > 0 ? "\(width)x\(height)" : "--")  帧率: \(Int(fps))fps  丢帧: \(Int(framesDropped))")
            lines.append("编码: \(codecName.isEmpty ? "--" : codecName)  解码器: \(decoderImpl.isEmpty ? "--" : decoderImpl)")
        }
        lines.append("码率: \(bitrateText)  延迟: \(rttMs >= 0 ? "\(Int(rttMs))ms" : "--")")
        lines.append("链路: \(connType)")
        return lines.joined(separator: "\n")
    }

    private static func formatBitrate(_ bps: Double) -> String {
        if bps >= 1_000_000 {
            return String(format: "%.1f Mbps", bps / 1_000_000)
        }
        if bps >= 1_000 {
            return String(format: "%.0f Kbps", bps / 1_000)
        }
        return String(format: "%.0f bps", bps)
    }
}

// MARK: - SignalingClientDelegate

extension ControllerViewModel: SignalingClientDelegate {

    func signalingDidConnect() {
        statusText = "信令已连接，正在发起会话..."
        startWebRTC()
    }

    func signalingDidDisconnect() {
        guard isConnecting || isControlling else { return }
        failConnection("信令服务器连接断开")
    }

    func signaling(didFail error: String) {
        guard isConnecting || isControlling else { return }
        failConnection("信令连接失败: \(error)")
    }

    func signaling(didReceive message: SignalMessage) {
        switch (message.type ?? "").uppercased() {
        case "ANSWER":
            if let sdp = message.payloadJSON()?["sdp"] as? String {
                statusText = "收到应答，正在协商..."
                webRTCClient?.handleAnswer(sdp: sdp)
            }
        case "ICE_CANDIDATE":
            if let json = message.payloadJSON(),
               let candidate = json["candidate"] as? String {
                let sdpMid = json["sdpMid"] as? String ?? ""
                let index = Int32((json["sdpMLineIndex"] as? NSNumber)?.intValue ?? 0)
                webRTCClient?.addIceCandidate(sdpMid: sdpMid, sdpMLineIndex: index, candidate: candidate)
            }
        case "TARGET_OFFLINE":
            failConnection("目标设备不在线")
        case "CONNECTION_REJECTED":
            let reason = message.payloadJSON()?["reason"] as? String
            failConnection(reason ?? "对方拒绝了连接请求")
        case "REQUEST_ERROR":
            let reason = message.payloadJSON()?["reason"] as? String
            failConnection(reason ?? "请求错误")
        case "REQUEST_TIMEOUT":
            failConnection("连接请求超时，对方未响应")
        default:
            break
        }
    }
}

// MARK: - WebRTCClientDelegate

extension ControllerViewModel: WebRTCClientDelegate {

    func webRTCClientDidConnect() {
        isConnecting = false
        isControlling = true
        statusText = "已连接: \(targetDeviceId)"
        applyStreamModeLocally(streamMode)
        startStatsTimer()
    }

    func webRTCClientDidDisconnect() {
        guard isControlling else { return }
        alertMessage = "连接已断开"
        disconnect()
    }

    func webRTCClient(didFail error: String) {
        failConnection(error)
    }

    func webRTCClient(didReportStreamMode mode: Int) {
        let reported = StreamMode(rawValue: mode) ?? .webrtc
        guard reported != streamMode else { return }
        // 与被控端实际模式同步（不再回发 SET_STREAM_MODE）
        suppressStreamModeSend = true
        streamMode = reported
        applyStreamModeLocally(reported)
        suppressStreamModeSend = false
    }

    func webRTCClient(didReportResolution width: Int, height: Int) {
        guard width > 0, height > 0 else { return }
        lastReportedWidth = Int32(width)
        lastReportedHeight = Int32(height)
        if streamMode == .webrtc {
            videoAspect = CGFloat(width) / CGFloat(height)
        }
    }

    func webRTCClient(didReportFps fps: Int, supportedFps: [Int]) {
        if fps > 0 { currentFps = fps }
        if !supportedFps.isEmpty { fpsOptions = supportedFps }
    }
}

// MARK: - RTCVideoViewDelegate（WebRTC 模式下画面尺寸变化）

extension ControllerViewModel: RTCVideoViewDelegate {

    func videoView(_ videoView: RTCVideoRenderer, didChangeVideoSize size: CGSize) {
        DispatchQueue.main.async {
            guard size.width > 0, size.height > 0 else { return }
            if self.streamMode == .webrtc {
                self.videoAspect = size.width / size.height
            }
        }
    }
}
