import UIKit

final class ExternalDisplayManager {
  static let shared = ExternalDisplayManager()

  private weak var activeCore: MpvPlayerCore?
  private var externalScene: UIWindowScene?
  private var externalWindow: UIWindow?
  private var externalRootViewController: UIViewController?

  private init() {}

  static func isExternalDisplayRole(_ role: UISceneSession.Role) -> Bool {
    role.rawValue == "UIWindowSceneSessionRoleExternalDisplay"
      || role.rawValue == "UIWindowSceneSessionRoleExternalDisplayNonInteractive"
  }

  static var hasActiveApplicationScene: Bool {
    applicationWindowScenes.contains { $0.activationState == .foregroundActive }
  }

  static func mainApplicationWindow() -> UIWindow? {
    let scenes = applicationWindowScenes.sorted {
      scenePriority($0.activationState) < scenePriority($1.activationState)
    }

    for scene in scenes {
      if let window = scene.windows.first(where: { $0.isKeyWindow }) {
        return window
      }
    }

    for scene in scenes {
      if let window = scene.windows.first(where: { !$0.isHidden }) {
        return window
      }
    }

    return scenes.first?.windows.first
  }

  private static var applicationWindowScenes: [UIWindowScene] {
    UIApplication.shared.connectedScenes.compactMap { scene in
      guard let windowScene = scene as? UIWindowScene,
        !isExternalDisplayRole(windowScene.session.role)
      else { return nil }
      return windowScene
    }
  }

  private static func scenePriority(_ state: UIScene.ActivationState) -> Int {
    switch state {
    case .foregroundActive:
      return 0
    case .foregroundInactive:
      return 1
    case .background:
      return 2
    case .unattached:
      return 3
    @unknown default:
      return 4
    }
  }

  var videoSuperview: UIView? {
    externalRootViewController?.view
  }

  func attach(core: MpvPlayerCore) {
    activeCore = core
    discoverExistingExternalScene()
    activeCore?.externalDisplayDidChange()
  }

  func detach(core: MpvPlayerCore) {
    if activeCore === core {
      activeCore = nil
    }
  }

  @discardableResult
  func connect(scene: UIWindowScene) -> UIWindow? {
    guard Self.isExternalDisplayRole(scene.session.role) else { return nil }

    externalScene = scene
    let window = ensureWindow(for: scene)
    activeCore?.externalDisplayDidChange()
    print("[ExternalDisplayManager] External display connected")
    return window
  }

  func disconnect(scene: UIScene) {
    guard scene === externalScene else { return }

    externalWindow?.isHidden = true
    externalWindow = nil
    externalRootViewController = nil
    externalScene = nil
    activeCore?.externalDisplayDidChange()
    print("[ExternalDisplayManager] External display disconnected")
  }

  func update(scene: UIWindowScene) {
    guard scene === externalScene else { return }
    externalRootViewController?.view.frame = scene.coordinateSpace.bounds
    activeCore?.externalDisplayDidChange()
  }

  private func discoverExistingExternalScene() {
    guard externalScene == nil else { return }

    for scene in UIApplication.shared.connectedScenes {
      guard let windowScene = scene as? UIWindowScene,
        Self.isExternalDisplayRole(windowScene.session.role)
      else { continue }
      _ = connect(scene: windowScene)
      return
    }
  }

  private func ensureWindow(for scene: UIWindowScene) -> UIWindow {
    if let existing = externalWindow, existing.windowScene === scene {
      return existing
    }

    externalWindow?.isHidden = true

    let rootViewController = UIViewController()
    rootViewController.view.frame = scene.coordinateSpace.bounds
    rootViewController.view.backgroundColor = .black

    let window = UIWindow(windowScene: scene)
    window.rootViewController = rootViewController
    window.backgroundColor = .black
    window.isHidden = false

    externalRootViewController = rootViewController
    externalWindow = window
    return window
  }
}

class ExternalDisplaySceneDelegate: UIResponder, UIWindowSceneDelegate {
  var window: UIWindow?

  func scene(
    _ scene: UIScene,
    willConnectTo session: UISceneSession,
    options connectionOptions: UIScene.ConnectionOptions
  ) {
    guard let windowScene = scene as? UIWindowScene,
      ExternalDisplayManager.isExternalDisplayRole(session.role)
    else { return }

    window = ExternalDisplayManager.shared.connect(scene: windowScene)
  }

  func sceneDidDisconnect(_ scene: UIScene) {
    ExternalDisplayManager.shared.disconnect(scene: scene)
    window = nil
  }

  func windowScene(
    _ windowScene: UIWindowScene,
    didUpdate previousCoordinateSpace: UICoordinateSpace,
    interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation,
    traitCollection previousTraitCollection: UITraitCollection
  ) {
    ExternalDisplayManager.shared.update(scene: windowScene)
  }
}
