import ExpoModulesCore
import AVKit
import MediaPlayer
import Network

// 确保导入Module类
@_exported import ExpoModulesCore

/**
 * ExpoDlnaPlayerModule - 支持AirPlay投屏的Expo原生模块
 *
 * 该模块实现了以下功能：
 * 1. 使用AVFoundation和MediaPlayer框架发现和连接AirPlay设备
 * 2. 通过Bonjour/Zeroconf协议(_raop._tcp服务)主动发现网络上的AirPlay设备
 * 3. 提供播放控制API，包括播放、暂停、停止、音量控制等
 * 4. 提供设备发现和连接状态管理
 *
 * 使用此模块需要在Info.plist中添加以下权限：
 * - NSLocalNetworkUsageDescription: 用于发现局域网内的AirPlay设备
 * - NSBonjourServices: 需要添加 _raop._tcp
 */

// 错误类型枚举
enum ExpoDlnaPlayerError: Error {
  case deviceNotFound
  case invalidURL
  case noDeviceConnected
  case connectionFailed
  case playbackFailed

  var localizedDescription: String {
    switch self {
    case .deviceNotFound:
      return "设备未找到"
    case .invalidURL:
      return "无效的URL"
    case .noDeviceConnected:
      return "未连接设备"
    case .connectionFailed:
      return "连接失败"
    case .playbackFailed:
      return "播放失败"
    }
  }
}

// 设备状态枚举
enum DeviceConnectionState: Equatable {
  case disconnected
  case connecting
  case connected
  case error(Error)

  static func == (lhs: DeviceConnectionState, rhs: DeviceConnectionState) -> Bool {
    switch (lhs, rhs) {
    case (.disconnected, .disconnected), (.connecting, .connecting), (.connected, .connected):
      return true
    case (.error(let lhsError), .error(let rhsError)):
      return lhsError.localizedDescription == rhsError.localizedDescription
    default:
      return false
    }
  }
}

// 设备类型枚举
enum DeviceType: String {
  case airplay = "airplay"
  case dlna = "dlna"
  case unknown = "unknown"
}

// 播放状态结构体
struct PlaybackState {
  var isPlaying: Bool = false
  var position: Double = 0
  var duration: Double = 0
  var volume: Double = 0
  var buffering: Bool = false
  var error: Error? = nil

  func toDictionary() -> [String: Any] {
    var dict: [String: Any] = [
      "isPlaying": isPlaying,
      "duration": duration,
      "position": position,
      "volume": volume,
      "buffering": buffering
    ]

    if let error = error {
      dict["error"] = error.localizedDescription
    }

    return dict
  }
}

// 配置结构体
private struct ModuleConfig {
  static let defaultVolume: Float = 1.0
  static let minVolume: Float = 0.0
  static let maxVolume: Float = 1.0
  static let defaultSeekInterval: TimeInterval = 10
  static let statusUpdateInterval: TimeInterval = 1.0
}

// 设备发现配置
private struct DiscoveryConfig {
  static let timeout: TimeInterval = 30
  static let retryCount = 3
  static let retryInterval: TimeInterval = 5
}

// 播放器配置
private struct PlayerConfig {
  static let bufferSize: Int = 5 // 缓冲区大小（秒）
  static let maxRetryCount: Int = 3 // 最大重试次数
  static let retryInterval: TimeInterval = 2.0 // 重试间隔（秒）
  static let discoveryTimeout: TimeInterval = 30.0 // 设备发现超时（秒）
  static let connectionTimeout: TimeInterval = 10.0 // 连接超时（秒）
}

// 1. 修复通知名称，使用官方常量
private extension Notification.Name {
  static let airPlayRouteChanged = Notification.Name("MPVolumeViewWirelessRouteActiveDidChange")
}

// 2. 添加线程安全队列保护共享资源
private let deviceListQueue = DispatchQueue(label: "com.expo.dlnaplayer.deviceList")

// 添加KVO观察者类
private class PlayerObserver: NSObject {
  weak var module: ExpoDlnaPlayerModule?
  
  init(module: ExpoDlnaPlayerModule) {
    self.module = module
    super.init()
  }
  
  override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard let module = module else { return }
    
    if let item = object as? AVPlayerItem {
      if keyPath == "status" {
        if item.status == .readyToPlay {
          module.log(.info, "播放器就绪")
        } else if item.status == .failed {
          module.log(.error, "播放器失败: \(String(describing: item.error))")
          module.sendErrorEvent(code: "PLAYER_ERROR", message: item.error?.localizedDescription ?? "播放失败")
        }
      } else if keyPath == "playbackBufferEmpty" {
        if item.isPlaybackBufferEmpty {
          module.log(.info, "播放缓冲为空，可能需要等待")
        }
      } else if keyPath == "playbackLikelyToKeepUp" {
        if item.isPlaybackLikelyToKeepUp {
          module.log(.info, "播放可能会继续进行")
        }
      } else if keyPath == "loadedTimeRanges" {
        let bufferedTime = module.getBufferedTime(item)
        module.log(.debug, "已缓冲时间: \(bufferedTime)秒")
      }
    }
  }
}

// 正确继承BaseModule并实现Module接口
public class ExpoDlnaPlayerModule: Module {
  // DLNA事件管理
  private var deviceList: [String: [String: Any]] = [:]
  private var currentDevice: [String: Any]? = nil
  private var connectionState: DeviceConnectionState = .disconnected
  private var player: AVPlayer? = nil
  private var playerStatusObserver: Any? = nil
  private var airplayStatusObserver: Any? = nil
  private var mediaUrl: URL? = nil
  private var mediaTitle: String? = nil
  private var mediaMimeType: String? = nil
  private var isDiscovering: Bool = false
  private var discoveryTimer: Timer?
  private var lastPlaybackState: PlaybackState?

  // 服务发现相关
  private var serviceBrowser: NetServiceBrowser?
  internal var discoveredServices: [NetService] = []

  // 添加KVO观察者
  private lazy var playerObserver = PlayerObserver(module: self)

  // 创建代理类来处理NetService相关回调
  private lazy var serviceDelegate = ServiceDelegate(module: self)

  // Each module class must implement the definition function. The definition consists of components
  // that describes the module's functionality and behavior.
  // See https://docs.expo.dev/modules/module-api for more details about available components.
  public func definition() -> ModuleDefinition {
    Name("ExpoDlnaPlayer")
    
    Events(
      "onDeviceFound",
      "onDeviceDisappeared",
      "onConnectionChanged",
      "onPlaybackStatusChanged",
      "onError",
      "onDiscoveryTimeout"
    )
    
    AsyncFunction("startDiscovery") { () -> Void in
      do {
        try self.startDiscovery()
      } catch {
        self.sendErrorEvent(code: "DISCOVERY_START_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("stopDiscovery") { () -> Void in
      do {
        try self.stopDiscovery()
      } catch {
        self.sendErrorEvent(code: "DISCOVERY_STOP_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("getDevices") { () -> [[String: Any]] in
      return Array(self.deviceList.values)
    }
    
    AsyncFunction("connectToDevice") { (deviceId: String) -> Bool in
      do {
        guard let device = self.deviceList[deviceId] else {
          throw ExpoDlnaPlayerError.deviceNotFound
        }

        self.connectionState = .connecting
        let result = try self.connectToDevice(device: device)

        if result {
          self.currentDevice = device
          self.connectionState = .connected
          self.sendEvent("onConnectionChanged", [
            "deviceId": deviceId,
            "connected": true
          ])
        } else {
          self.connectionState = .disconnected
        }

        return result
      } catch {
        self.connectionState = .error(error)
        self.sendErrorEvent(code: "CONNECTION_ERROR", message: error.localizedDescription, deviceId: deviceId)
        throw error
      }
    }
    
    AsyncFunction("disconnectFromDevice") { () -> Void in
      do {
        guard let device = self.currentDevice,
              let deviceId = device["id"] as? String else {
          return
        }

        try self.disconnectFromDevice()
        self.currentDevice = nil
        self.connectionState = .disconnected

        self.sendEvent("onConnectionChanged", [
          "deviceId": deviceId,
          "connected": false
        ])
      } catch {
        self.sendErrorEvent(code: "DISCONNECT_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("isConnected") { () -> Bool in
      return self.connectionState == .connected
    }
    
    AsyncFunction("getConnectedDevice") { () -> [String: Any]? in
      return self.currentDevice
    }
    
    AsyncFunction("play") { (url: String, title: String?, mimeType: String?) -> Void in
      do {
        guard let currentDevice = self.currentDevice else {
          throw ExpoDlnaPlayerError.noDeviceConnected
        }

        guard let mediaURL = URL(string: url) else {
          throw ExpoDlnaPlayerError.invalidURL
        }

        self.mediaUrl = mediaURL
        self.mediaTitle = title ?? "未知标题"
        self.mediaMimeType = mimeType ?? self.guessMimeType(from: url)

        try self.play(url: mediaURL, title: self.mediaTitle, mimeType: self.mediaMimeType)
        self.updatePlaybackStatus()
      } catch {
        self.sendErrorEvent(code: "PLAY_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("pause") { () -> Void in
      do {
        if self.currentDevice == nil {
          throw ExpoDlnaPlayerError.noDeviceConnected
        }

        try self.pause()
        self.updatePlaybackStatus()
      } catch {
        self.sendErrorEvent(code: "PAUSE_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("resume") { () -> Void in
      do {
        if self.currentDevice == nil {
          throw ExpoDlnaPlayerError.noDeviceConnected
        }

        try self.resume()
        self.updatePlaybackStatus()
      } catch {
        self.sendErrorEvent(code: "RESUME_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("stop") { () -> Void in
      do {
        if self.currentDevice == nil {
          throw ExpoDlnaPlayerError.noDeviceConnected
        }

        try self.stop()
        self.updatePlaybackStatus()
      } catch {
        self.sendErrorEvent(code: "STOP_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("seek") { (position: Double) -> Void in
      do {
        if self.currentDevice == nil {
          throw ExpoDlnaPlayerError.noDeviceConnected
        }

        try self.seek(position: position)
        self.updatePlaybackStatus()
      } catch {
        self.sendErrorEvent(code: "SEEK_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("setVolume") { (volume: Double) -> Void in
      do {
        if self.currentDevice == nil {
          throw ExpoDlnaPlayerError.noDeviceConnected
        }

        try self.setVolume(volume: volume)
        self.updatePlaybackStatus()
      } catch {
        self.sendErrorEvent(code: "VOLUME_ERROR", message: error.localizedDescription)
        throw error
      }
    }
    
    AsyncFunction("getPlaybackStatus") { () -> [String: Any] in
      do {
        if self.currentDevice == nil {
          throw ExpoDlnaPlayerError.noDeviceConnected
        }

        return try self.getPlaybackStatus()
      } catch {
        self.sendErrorEvent(code: "STATUS_ERROR", message: error.localizedDescription)
        throw error
      }
    }
  }

  // 设备发现与连接管理
  private func startDiscovery() throws {
    log(.info, "开始AirPlay设备发现...")
    isDiscovering = true

    // 检查并请求本地网络权限
    checkAndRequestLocalNetworkPermission()

    // 设置音频会话
    do {
      try initializeAudioSession()
    } catch {
      log(.error, "设置音频会话失败: \(error)")
      isDiscovering = false
      throw error
    }

    // 在iOS上，使用更现代的方法检测设备
    if #available(iOS 14.0, *) {
      // iOS 14+使用AVRouteDetector和AVRoutePickerView
      let routeDetector = AVRouteDetector()
      let _ = routeDetector.multipleRoutesDetected // 触发设备检测

      // 不需要在这里创建视图，只是为了使用其API
      _ = setupAVRoutePickerView()
    } else {
      // 旧版iOS兼容方案
    let volumeView = MPVolumeView()
      volumeView.showsVolumeSlider = false
    volumeView.showsRouteButton = true
    }

    // 检查当前是否有可用的AirPlay设备
    let _ = checkForAirPlayDevices()

    // 监听AirPlay状态变化
    setupAirPlayObservers()

    // 使用Bonjour主动发现AirPlay设备
    startNetServiceDiscovery()

    // 设置发现超时
    setupDiscoveryTimeout()
  }

  // 停止设备发现
  private func stopDiscovery() throws {
    log(.info, "停止设备发现")
    isDiscovering = false

    // 停止服务发现
    stopNetServiceDiscovery()

    // 移除观察者
    if let observer = airplayStatusObserver {
      NotificationCenter.default.removeObserver(observer)
      airplayStatusObserver = nil
    }

    // 取消定时器
    discoveryTimer?.invalidate()
    discoveryTimer = nil
  }

  // 代理类，使用NSObject来处理NetService回调
  private class ServiceDelegate: NSObject, NetServiceBrowserDelegate, NetServiceDelegate {
    weak var module: ExpoDlnaPlayerModule?
    
    init(module: ExpoDlnaPlayerModule) {
      self.module = module
      super.init()
    }
    
    public func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
      guard let dlnaModule = module else { return }
      
      dlnaModule.log(.info, "发现服务: \(service.name) - \(service.type)")
      
      // 将服务添加到列表并开始解析
      service.delegate = self
      dlnaModule.discoveredServices.append(service)
      service.resolve(withTimeout: 5.0)
    }
    
    public func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
      guard let dlnaModule = module else { return }
      
      dlnaModule.log(.info, "服务已移除: \(service.name)")
      
      // 从列表中移除服务
      if let index = dlnaModule.discoveredServices.firstIndex(where: { $0 == service }) {
        dlnaModule.discoveredServices.remove(at: index)
      }
      
      // 构建设备ID
      let deviceId = "airplay-\(service.name.lowercased().replacingOccurrences(of: " ", with: "-"))"
      
      // 使用线程安全方法移除设备
      dlnaModule.removeDeviceFromList(withId: deviceId)
    }
    
    public func netServiceDidResolveAddress(_ service: NetService) {
      guard let dlnaModule = module else { return }
      
      dlnaModule.log(.info, "服务已解析: \(service.name), 主机: \(service.hostName ?? "未知"), 端口: \(service.port)")

      // 从服务TXT记录中获取设备信息
      var deviceInfo: [String: String] = [:]
      if let txtData = service.txtRecordData() {
        deviceInfo = NetService.dictionary(fromTXTRecord: txtData) as? [String: String] ?? [:]
      }

      // 构建设备ID
      let deviceId = "airplay-\(service.name.lowercased().replacingOccurrences(of: " ", with: "-"))"

      // 获取IP地址
      var ipAddress = service.hostName ?? "未知"
      if let addresses = service.addresses, !addresses.isEmpty {
        // 尝试从地址数据中提取IP
        for addressData in addresses {
          var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
          let result = addressData.withUnsafeBytes { pointer in
              let sockaddrPtr = pointer.bindMemory(to: sockaddr.self).baseAddress!
              return getnameinfo(sockaddrPtr, socklen_t(addressData.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST)
          }

          if result == 0 {
              ipAddress = String(cString: hostname)
              break
          }
        }
      }

      // 提取设备型号和制造商信息
      let model = deviceInfo["model"] ?? deviceInfo["am"] ?? "AirPlay"
      let manufacturer = deviceInfo["manufacturer"] ?? "Apple"

      // 创建设备信息
      let airPlayDevice: [String: Any] = [
        "id": deviceId,
        "name": service.name,
        "model": model,
        "manufacturer": manufacturer,
        "ipAddress": ipAddress,
        "port": service.port,
        "type": DeviceType.airplay.rawValue
      ]

      // 使用线程安全方法添加到设备列表
      dlnaModule.addDeviceToList(airPlayDevice, withId: deviceId)
    }

    public func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber]) {
      guard let dlnaModule = module else { return }
      
      dlnaModule.log(.error, "服务解析失败: \(sender.name), 错误: \(errorDict)")
    }
  }

  // 开始NetService发现
  private func startNetServiceDiscovery() {
    // 创建服务浏览器
    serviceBrowser = NetServiceBrowser()
    serviceBrowser?.delegate = serviceDelegate

    // 开始浏览_raop._tcp服务（AirPlay音频设备）
    log(.info, "开始浏览_raop._tcp服务")
    serviceBrowser?.searchForServices(ofType: "_raop._tcp.", inDomain: "local.")
  }

  private func stopNetServiceDiscovery() {
    serviceBrowser?.stop()
    serviceBrowser = nil

    // 移除所有服务解析代理
    for service in discoveredServices {
      service.delegate = nil
      service.stop()
    }
    discoveredServices.removeAll()
  }

  // 媒体播放控制
  private func play(url: URL, title: String?, mimeType: String?) throws {
    let safeTitle = title ?? "未知标题"
    let safeMimeType = mimeType ?? guessMimeType(from: url.absoluteString)
    
    mediaUrl = url
    mediaTitle = safeTitle
    mediaMimeType = safeMimeType

    log(.info, "开始播放媒体: \(safeTitle), URL: \(url.absoluteString)")

    // 检查播放器是否存在
    guard let player = player else {
      throw ExpoDlnaPlayerError.noDeviceConnected
    }

    // 分离播放项设置为独立函数
    let playerItem = createPlayerItem(for: url)

    // 设置播放完成和失败的观察者
    setupPlaybackObservers(for: playerItem, url: url, title: title, mimeType: mimeType)

    player.replaceCurrentItem(with: playerItem)
    player.play()

    // 设置锁屏界面信息
    setupMediaInfo(title: safeTitle)
  }
  
  // 创建播放项，带有适当的设置
  private func createPlayerItem(for url: URL) -> AVPlayerItem {
    var playerItem = AVPlayerItem(url: url)

    // 设置缓冲区大小
    playerItem.preferredForwardBufferDuration = TimeInterval(PlayerConfig.bufferSize)

    // 设置HTTP头部，帮助某些流媒体服务器
    let headers: [String: String] = [
      "User-Agent": "Expo-DLNA-Player/1.0"
    ]

    // 为HLS流设置额外选项
    if url.absoluteString.contains(".m3u8") {
      // 使用AVURLAsset的正确常量定义
      let headerKey = "AVURLAssetHTTPHeaderFieldsKey"
      let options: [String: Any] = [
        headerKey: headers,
        AVURLAssetPreferPreciseDurationAndTimingKey: true
      ]

      let urlAsset = AVURLAsset(url: url, options: options)
      playerItem = AVPlayerItem(asset: urlAsset)
    }
    
    return playerItem
  }
  
  // 为播放项设置观察者
  private func setupPlaybackObservers(for playerItem: AVPlayerItem, url: URL, title: String?, mimeType: String?) {
    // 记录重试次数，避免在闭包中捕获修改
    var retryCount = 0
    let maxRetryCount = PlayerConfig.maxRetryCount
    
    // 添加播放完成通知
    setupPlayToEndObserver(for: playerItem)
    
    // 添加播放失败通知
    setupFailureObserver(for: playerItem, url: url, title: title, mimeType: mimeType, retryCount: &retryCount, maxRetryCount: maxRetryCount)
  }
  
  // 设置播放完成观察者
  private func setupPlayToEndObserver(for item: AVPlayerItem) {
    NotificationCenter.default.addObserver(
      forName: .AVPlayerItemDidPlayToEndTime,
      object: item,
      queue: .main,
      using: { [weak self] _ in
        self?.handlePlayToEnd()
      }
    )
  }
  
  // 处理播放结束事件
  private func handlePlayToEnd() {
    log(.info, "播放已完成")
    sendEvent("onPlaybackStatusChanged", ["isPlaying": false, "completed": true])
  }
  
  // 设置播放失败观察者
  private func setupFailureObserver(for item: AVPlayerItem, url: URL, title: String?, mimeType: String?, retryCount: inout Int, maxRetryCount: Int) {
    // 创建一个本地变量存储retryCount的值
    let localRetryCount = retryCount
    
    NotificationCenter.default.addObserver(
      forName: .AVPlayerItemFailedToPlayToEndTime,
      object: item,
      queue: .main,
      using: { [weak self] notification in
        // 调用一个新的处理方法，不再直接传入inout参数
        self?.handlePlaybackFailureWithRetry(notification: notification, url: url, title: title, mimeType: mimeType, initialRetryCount: localRetryCount, maxRetryCount: maxRetryCount)
      }
    )
  }
  
  // 新增一个不使用inout参数的处理方法
  private func handlePlaybackFailureWithRetry(notification: Notification, url: URL, title: String?, mimeType: String?, initialRetryCount: Int, maxRetryCount: Int) {
    guard let error = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? Error else { return }
    
    log(.error, "播放失败: \(error.localizedDescription)")

    // 自动重试
    if initialRetryCount < maxRetryCount {
      let newRetryCount = initialRetryCount + 1
      log(.info, "尝试重新播放 (\(newRetryCount)/\(maxRetryCount))")

      // 延迟一会再重试
      DispatchQueue.main.asyncAfter(deadline: .now() + PlayerConfig.retryInterval) { [weak self] in
        try? self?.play(url: url, title: title, mimeType: mimeType)
      }
    } else {
      sendErrorEvent(code: "PLAYBACK_FAILED", message: error.localizedDescription)
    }
  }

  // 原有的处理方法保留但需修改适应新的架构
  private func handlePlaybackFailure(notification: Notification, url: URL, title: String?, mimeType: String?, retryCount: inout Int, maxRetryCount: Int) {
    guard let error = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? Error else { return }
    
    log(.error, "播放失败: \(error.localizedDescription)")

    // 自动重试
    if retryCount < maxRetryCount {
      retryCount += 1
      log(.info, "尝试重新播放 (\(retryCount)/\(maxRetryCount))")

      // 延迟一会再重试
      DispatchQueue.main.asyncAfter(deadline: .now() + PlayerConfig.retryInterval) { [weak self] in
        try? self?.play(url: url, title: title, mimeType: mimeType)
      }
    } else {
      sendErrorEvent(code: "PLAYBACK_FAILED", message: error.localizedDescription)
    }
  }

  // 检查当前是否有可用的AirPlay设备
  private func checkForAirPlayRoutesAvailable() -> Bool {
    // 使用AVRouteDetector替代deprecated的MPVolumeView方法
    if #available(iOS 11.0, *) {
      let routeDetector = AVRouteDetector()
      return routeDetector.multipleRoutesDetected
    } else {
      // 旧版iOS兼容方案 - 修复routeButtonRect使用方法
      let volumeView = MPVolumeView()
      // 不要直接访问routeButtonRect属性，而是调用方法
      let buttonFrame = volumeView.routeButtonRect(forBounds: volumeView.bounds)
      return buttonFrame.width > 0
    }
  }

  // iOS 14+新API的支持
  @available(iOS 14.0, *)
  private func setupAVRoutePickerView() -> UIView {
    let routePickerView = AVRoutePickerView()
    routePickerView.activeTintColor = UIColor.systemBlue
    routePickerView.prioritizesVideoDevices = true // 优先视频设备
    return routePickerView
  }

  // 设置发现超时
  private func setupDiscoveryTimeout() {
    // 取消任何现有的超时定时器
    discoveryTimer?.invalidate()

    // 设置新的超时定时器
    discoveryTimer = Timer.scheduledTimer(withTimeInterval: PlayerConfig.discoveryTimeout, repeats: false) { [weak self] _ in
      guard let self = self else { return }

      // 只有在仍在发现状态时才停止
      if self.isDiscovering {
        self.log(.info, "设备发现超时，停止搜索")
        try? self.stopDiscovery()

        // 发送超时事件
        self.sendEvent("onDiscoveryTimeout", [:])
      }
    }
  }

  // 其他可能抛出异常的地方，确保使用try
  private func initializeAudioSession() throws {
    let audioSession = AVAudioSession.sharedInstance()
    try audioSession.setCategory(.playback, mode: .default, options: [.allowAirPlay])
    try audioSession.setActive(true)
  }

  // 设备验证
  private func validateDevice(_ device: [String: Any]) -> Bool {
    guard let id = device["id"] as? String,
          let name = device["name"] as? String,
          !id.isEmpty,
          !name.isEmpty else {
      log(.warning, "无效的设备信息")
      return false
    }
    return true
  }

  // 媒体播放控制
  private func pause() throws {
    log(.info, "暂停播放")
    player?.pause()
  }

  private func resume() throws {
    log(.info, "恢复播放")
    player?.play()
  }

  private func stop() {
    log(.info, "停止播放")
    player?.pause()
    player?.seek(to: CMTime.zero)
  }

  private func seek(position: Double) throws {
    log(.info, "跳转到位置: \(position)秒")
    let time = CMTime(seconds: position, preferredTimescale: 1)
    player?.seek(to: time)
  }

  private func setVolume(volume: Double) throws {
    let safeVolume = max(ModuleConfig.minVolume, min(ModuleConfig.maxVolume, Float(volume / 100.0)))
    log(.info, "设置音量: \(safeVolume)")
    player?.volume = safeVolume
  }

  private func getPlaybackStatus() throws -> [String: Any] {
    var state = PlaybackState()

    if let player = player {
      if let currentItem = player.currentItem {
        let currentTime = currentItem.currentTime()
        state.position = CMTimeGetSeconds(currentTime)

        if let durationTime = currentItem.duration.isValid ? currentItem.duration : nil {
          state.duration = CMTimeGetSeconds(durationTime)
        }

        state.buffering = currentItem.isPlaybackBufferEmpty
      }

      state.isPlaying = player.rate > 0
      state.volume = Double(player.volume) * 100
    }

    lastPlaybackState = state
    return state.toDictionary()
  }

  // 辅助方法
  private func setupMediaInfo(title: String?) {
    let safeTitle = title ?? "未知标题"
    var nowPlayingInfo: [String: Any] = [
      MPMediaItemPropertyTitle: safeTitle
    ]

    // 添加持续时间
    if let duration = player?.currentItem?.duration.seconds, !duration.isNaN, duration > 0 {
      nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = duration
    }

    // 添加播放位置
    if let position = player?.currentTime().seconds, !position.isNaN {
      nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = position
    }

    // 添加播放速率
    nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player?.rate ?? 1.0

    // 设置媒体控制中心的信息
    MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo

    // 启用远程控制事件
    UIApplication.shared.beginReceivingRemoteControlEvents()
  }

  private func updatePlaybackStatus() {
    DispatchQueue.main.async { [weak self] in
      guard let self = self else { return }

      do {
        // 获取当前播放状态
        let status = try self.getPlaybackStatus()

        // 检查状态是否有变化
        if let lastState = self.lastPlaybackState {
          let currentState = try self.getPlaybackState()

          // 只有当状态有变化时才发送事件，减少无谓的更新
          if currentState.isPlaying != lastState.isPlaying ||
             abs(currentState.position - lastState.position) > 1.0 ||
             abs(currentState.duration - lastState.duration) > 1.0 ||
             abs(currentState.volume - lastState.volume) > 1.0 ||
             currentState.buffering != lastState.buffering {
            self.sendEvent("onPlaybackStatusChanged", status)
          }
        } else {
          // 首次获取状态，直接发送
          self.sendEvent("onPlaybackStatusChanged", status)
        }
      } catch {
        self.log(.error, "更新播放状态失败: \(error)")
      }
    }
  }

  private func getPlaybackState() throws -> PlaybackState {
    var state = PlaybackState()

    if let player = player {
      if let currentItem = player.currentItem {
        let currentTime = currentItem.currentTime()
        state.position = CMTimeGetSeconds(currentTime)

        if let durationTime = currentItem.duration.isValid ? currentItem.duration : nil {
          state.duration = CMTimeGetSeconds(durationTime)
        }

        state.buffering = currentItem.isPlaybackBufferEmpty
      }

      state.isPlaying = player.rate > 0
      state.volume = Double(player.volume) * 100
    }

    return state
  }

  private func guessMimeType(from url: String) -> String {
    if url.hasSuffix(".mp4") {
      return "video/mp4"
    } else if url.hasSuffix(".m3u8") {
      return "application/x-mpegURL"
    } else if url.hasSuffix(".mpd") {
      return "application/dash+xml"
    } else if url.hasSuffix(".mp3") {
      return "audio/mpeg"
    } else if url.hasSuffix(".wav") {
      return "audio/wav"
    } else if url.hasSuffix(".jpg") || url.hasSuffix(".jpeg") {
      return "image/jpeg"
    } else if url.hasSuffix(".png") {
      return "image/png"
    } else {
      return "video/mp4" // 默认视频类型
    }
  }

  // 获取缓冲时间 - 改为internal，让PlayerObserver可以调用
  internal func getBufferedTime(_ item: AVPlayerItem) -> TimeInterval {
    if let timeRange = item.loadedTimeRanges.first as? CMTimeRange {
      let bufferedSeconds = CMTimeGetSeconds(timeRange.duration)
      return bufferedSeconds
    }
    return 0
  }

  // 修改为internal让PlayerObserver可以调用
  internal func sendErrorEvent(code: String, message: String, deviceId: String? = nil) {
    var params: [String: Any] = [
      "code": code,
      "message": message
    ]

    if let deviceId = deviceId {
      params["deviceId"] = deviceId
    }

    log(.error, "发送错误事件: \(code) - \(message)")
    sendEvent("onError", params)
  }

  // 检查当前是否有可用的AirPlay设备
  private func checkForAirPlayDevices() -> Bool {
    log(.info, "检查可用的AirPlay设备...")

    // 获取当前音频输出路由
    let audioSession = AVAudioSession.sharedInstance()
    let currentRoute = audioSession.currentRoute

    // 检查是否有AirPlay输出
    var hasAirPlayOutput = false
    for output in currentRoute.outputs {
      if output.portType == AVAudioSession.Port.airPlay {
        hasAirPlayOutput = true

        // 创建或更新AirPlay设备信息
        let deviceId = "airplay-\(output.portName.lowercased().replacingOccurrences(of: " ", with: "-"))"

        // 如果该设备还没被发现，添加到设备列表
        if deviceList[deviceId] == nil {
          let airPlayDevice: [String: Any] = [
            "id": deviceId,
            "name": output.portName,
            "model": "AirPlay Device",
            "manufacturer": "Apple",
            "ipAddress": "未知", // AirPlay不直接提供IP地址
            "port": 0,
            "type": DeviceType.airplay.rawValue
          ]

          log(.info, "发现AirPlay输出设备: \(output.portName)")
          deviceList[deviceId] = airPlayDevice
          sendEvent("onDeviceFound", airPlayDevice)
        }

        // 如果这是当前正在使用的设备，更新连接状态
        if connectionState != .connected {
          connectionState = .connected
          currentDevice = deviceList[deviceId]
          sendEvent("onConnectionChanged", [
            "deviceId": deviceId,
            "connected": true
          ])
        }
      }
    }

    // 如果没有找到AirPlay输出但曾经连接过，则认为设备已断开
    if !hasAirPlayOutput && connectionState == .connected {
      if let currentDevice = currentDevice, let deviceId = currentDevice["id"] as? String {
        connectionState = .disconnected
        self.currentDevice = nil
        sendEvent("onConnectionChanged", [
          "deviceId": deviceId,
          "connected": false
        ])
      }
    }

    return hasAirPlayOutput
  }

  private func connectToDevice(device: [String: Any]) throws -> Bool {
    // 对于AirPlay，我们需要确保设备连接并准备AVPlayer
    guard let deviceType = device["type"] as? String else {
      throw ExpoDlnaPlayerError.deviceNotFound
    }

    if deviceType == DeviceType.airplay.rawValue {
      log(.info, "连接到AirPlay设备: \(device["name"] as? String ?? "未知设备")")

      // 创建播放器
      player = AVPlayer()

      // 设置播放器观察者
      setupPlayerObservers()

      // 设置音频会话以允许AirPlay
      try initializeAudioSession()

      // 开启屏幕镜像系统UI - 替换已废弃的API
      if #available(iOS 14.0, *) {
        // iOS 14及以上使用AVRoutePickerView
        let _ = setupAVRoutePickerView()
        // 注意: 实际上是系统会管理路由选择，我们不需要手动显示此视图
      } else {
        // 旧版iOS兼容
        let routeButton = MPVolumeView()
        routeButton.showsRouteButton = true
      }

      connectionState = .connected
      return true
    } else {
      // 其他设备类型
      log(.warning, "不支持的设备类型: \(deviceType)")
      return false
    }
  }

  private func disconnectFromDevice() throws {
    stop()

    if let observer = playerStatusObserver {
      player?.removeTimeObserver(observer)
      playerStatusObserver = nil
    }

    player = nil
    connectionState = .disconnected
  }

  // 资源清理方法
  private func cleanup() {
    // 分步清理各种资源
    stopPlayback()
    removeObservers()
    clearDeviceData()
    clearMediaData()

    log(.info, "资源已完全清理")
  }
  
  private func stopPlayback() {
    // 停止播放
    player?.pause()
    player = nil
  }
  
  private func removeObservers() {
    // 移除播放器时间观察者
    removePlayerTimeObserver()
    
    // 移除KVO观察者
    removePlayerItemObservers()
    
    // 移除通知中心观察者
    removeNotificationObservers()
  }
  
  private func removePlayerItemObservers() {
    // 移除播放器项目KVO观察
    guard let currentItem = player?.currentItem else { return }
    
    let keyPaths: [String] = [
      "status", 
      "playbackBufferEmpty", 
      "playbackLikelyToKeepUp", 
      "loadedTimeRanges"
    ]
    
    for keyPath in keyPaths {
      currentItem.removeObserver(playerObserver, forKeyPath: keyPath)
    }
  }
  
  private func removeNotificationObservers() {
    // 移除AirPlay状态观察者
    if let observer = airplayStatusObserver {
      NotificationCenter.default.removeObserver(observer)
      airplayStatusObserver = nil
    }
    
    // 移除其他通知观察者
    let notificationNames: [Notification.Name] = [
      AVAudioSession.routeChangeNotification,
      AVAudioSession.interruptionNotification,
      AVAudioSession.mediaServicesWereResetNotification
    ]
    
    for name in notificationNames {
      NotificationCenter.default.removeObserver(self, name: name, object: nil)
    }
  }
  
  private func clearDeviceData() {
    // 停止发现计时器
    discoveryTimer?.invalidate()
    discoveryTimer = nil
    isDiscovering = false

    // 清理设备列表
    deviceListQueue.sync {
      deviceList.removeAll()
    }
    currentDevice = nil
    connectionState = .disconnected
  }
  
  private func clearMediaData() {
    // 清理媒体信息
    mediaUrl = nil
    mediaTitle = nil
    mediaMimeType = nil
    lastPlaybackState = nil
  }

  // 日志系统
  internal enum LogLevel {
    case debug
    case info
    case warning
    case error
  }

  internal func log(_ level: LogLevel, _ message: String, file: String = #file, function: String = #function, line: Int = #line) {
    let fileName = (file as NSString).lastPathComponent
    let timestamp = DateFormatter.localizedString(from: Date(), dateStyle: .none, timeStyle: .medium)

    var prefix = ""
    switch level {
    case .debug:
      prefix = "📘 DEBUG"
    case .info:
      prefix = "📗 INFO"
    case .warning:
      prefix = "📙 WARNING"
    case .error:
      prefix = "📕 ERROR"
    }

    let logMessage = "[\(timestamp)] \(prefix) [\(fileName):\(line)] \(function): \(message)"
    print(logMessage)
  }

  // URL验证
  private func validateURL(_ urlString: String) -> Bool {
    guard let url = URL(string: urlString),
          let scheme = url.scheme,
          ["http", "https"].contains(scheme.lowercased()) else {
      log(.warning, "无效的URL: \(urlString)")
      return false
    }
    return true
  }

  // 设置播放器观察者
  private func setupPlayerObservers() {
    // 移除旧观察者
    removePlayerTimeObserver()
    
    // 添加新的时间观察者
    addPlayerTimeObserver()
    
    // 添加播放器状态观察
    addPlayerItemObservers()
  }
  
  private func removePlayerTimeObserver() {
    if let observer = playerStatusObserver {
      player?.removeTimeObserver(observer)
      playerStatusObserver = nil
    }
  }
  
  private func addPlayerTimeObserver() {
    // 显式类型注解
    let timeInterval: CMTime = CMTime(seconds: 0.5, preferredTimescale: 600)
    
    playerStatusObserver = player?.addPeriodicTimeObserver(
      forInterval: timeInterval,
      queue: DispatchQueue.main,
      using: { [weak self] _ in
        self?.updatePlaybackStatus()
      }
    )
  }
  
  private func addPlayerItemObservers() {
    guard let currentItem = player?.currentItem else { return }
    
    // 使用我们的专用观察者类，避免内存泄漏
    let keyPaths: [String] = [
      "status", 
      "playbackBufferEmpty", 
      "playbackLikelyToKeepUp", 
      "loadedTimeRanges"
    ]
    
    for keyPath in keyPaths {
      currentItem.addObserver(
        playerObserver,
        forKeyPath: keyPath,
        options: [.new],
        context: nil
      )
    }
  }

  // 改进监听器设置，添加各种状态变化的观察
  private func setupAirPlayObservers() {
    // 移除旧观察器以防重复
    if let observer = airplayStatusObserver {
      NotificationCenter.default.removeObserver(observer)
    }

    // 监听AirPlay状态变化
    airplayStatusObserver = NotificationCenter.default.addObserver(
      forName: .airPlayRouteChanged,
      object: nil,
      queue: OperationQueue.main
    ) { [weak self] _ in
      self?.checkForAirPlayDevices()
    }

    // 添加路由变更通知，可以捕获更多设备变化
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(handleRouteChange),
      name: AVAudioSession.routeChangeNotification,
      object: nil
    )

    // 添加中断通知监听，处理播放中断
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(handleAudioSessionInterruption),
      name: AVAudioSession.interruptionNotification,
      object: nil
    )

    // 媒体服务重置通知
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(handleMediaServicesReset),
      name: AVAudioSession.mediaServicesWereResetNotification,
      object: nil
    )
  }

  // 处理音频会话中断
  @objc private func handleAudioSessionInterruption(notification: Notification) {
    guard let userInfo = notification.userInfo,
          let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
          let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
      return
    }

    if type == .began {
      // 中断开始，暂停播放
      log(.info, "音频会话被中断，暂停播放")
      try? pause()
    } else if type == .ended {
      // 中断结束，检查是否应该恢复播放
      if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
        let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
        if options.contains(.shouldResume) {
          log(.info, "音频中断结束，恢复播放")
          try? resume()
        }
      }
    }
  }

  // 处理媒体服务重置
  @objc private func handleMediaServicesReset(notification: Notification) {
    log(.info, "媒体服务已重置，重新初始化播放器")

    // 保存当前状态
    let wasPlaying = player?.rate ?? 0 > 0
    let currentPosition = player?.currentTime().seconds ?? 0
    let currentUrl = mediaUrl
    let currentTitle = mediaTitle
    let currentMimeType = mediaMimeType

    // 重新创建播放器
    player = AVPlayer()

    // 如果有媒体正在播放，尝试恢复
    if let url = currentUrl, wasPlaying {
      try? self.play(url: url, title: currentTitle ?? "未知媒体", mimeType: currentMimeType ?? "video/mp4")
      self.player?.seek(to: CMTime(seconds: currentPosition, preferredTimescale: 600))
    }

    // 重新设置观察者
    setupPlayerObservers()
  }

  // 处理路由变化
  @objc private func handleRouteChange(notification: Notification) {
    guard let userInfo = notification.userInfo,
          let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
          let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
      return
    }

    log(.info, "音频路由变化: \(reason)")

    // 处理不同的路由变化原因
    switch reason {
    case .newDeviceAvailable:
      // 新设备可用，如连接了AirPlay
      log(.info, "新音频设备可用")
      checkForAirPlayDevices()

    case .oldDeviceUnavailable:
      // 设备不可用，如断开了AirPlay
      log(.info, "音频设备不可用")
      checkForAirPlayDevices()

    case .categoryChange:
      // 音频类别变化
      log(.info, "音频类别变化")

    case .override:
      // 路由被覆盖，例如用户手动切换了目标设备
      log(.info, "音频路由被覆盖")
      checkForAirPlayDevices()

    case .wakeFromSleep:
      // 从睡眠唤醒
      log(.info, "从睡眠唤醒，重新检查设备")
      checkForAirPlayDevices()

    case .noSuitableRouteForCategory:
      // 当前类别没有合适的路由
      log(.info, "没有合适的音频路由")

    case .routeConfigurationChange:
      // 路由配置变化但不需要重新连接
      log(.info, "音频路由配置变化")

    default:
      log(.info, "未处理的音频路由变化原因: \(reason)")
    }
  }

  // 修改添加设备到列表的方法，使用队列保护
  internal func addDeviceToList(_ device: [String: Any], withId deviceId: String) {
    deviceListQueue.sync {
      let isNew = deviceList[deviceId] == nil
      deviceList[deviceId] = device

      if isNew {
        if let name = device["name"] as? String {
          log(.info, "发现设备: \(name)")
        }
        sendEvent("onDeviceFound", device)
      }
    }
  }

  // 修改移除设备的方法，使用队列保护
  internal func removeDeviceFromList(withId deviceId: String) {
    deviceListQueue.sync {
      if deviceList[deviceId] != nil {
        deviceList.removeValue(forKey: deviceId)
        sendEvent("onDeviceDisappeared", ["deviceId": deviceId])

        // 如果断开的是当前连接的设备，发送连接变化事件
        if let currentDevice = currentDevice,
           let currentId = currentDevice["id"] as? String,
           currentId == deviceId {
          self.currentDevice = nil
          connectionState = .disconnected

          sendEvent("onConnectionChanged", [
            "deviceId": deviceId,
            "connected": false
          ])
        }
      }
    }
  }

  // 添加deinit方法确保资源释放
  deinit {
    cleanup()
  }

  // 检查并请求本地网络权限
  private func checkAndRequestLocalNetworkPermission() {
    if #available(iOS 14.0, *) {
      // 创建网络路径监视器来检查和触发权限
      let localNetworkPrivacyAlert = NWPathMonitor(requiredInterfaceType: .wifi)
      
      // 监听网络路径更新
      localNetworkPrivacyAlert.pathUpdateHandler = { [weak self] path in
        guard let self = self else { return }
        
        // 权限状态检查
        if path.status == .satisfied {
          // 网络连接正常，可能已授权
          self.log(.info, "本地网络权限可能已获得")
          self.sendEvent("onPermissionStatus", ["permission": "localNetwork", "status": "granted"])
        } else if path.status == .unsatisfied {
          // 网络连接不满足条件，可能是权限被拒绝
          self.log(.warning, "本地网络权限可能被拒绝")
          self.sendEvent("onPermissionStatus", ["permission": "localNetwork", "status": "denied"])
          
          // 通知用户权限被拒绝
          self.sendEvent("onError", [
            "code": "PERMISSION_DENIED", 
            "message": "本地网络权限被拒绝，无法发现设备。请在设置中允许此应用访问本地网络。"
          ])
        }
        
        // 停止监听，避免持续接收更新
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
          localNetworkPrivacyAlert.cancel()
        }
      }
      
      // 启动监视器
      localNetworkPrivacyAlert.start(queue: DispatchQueue.global())
    }
  }
}
