import AppKit
import SwiftUI
import Combine

/// Manages standalone pop-out terminal windows for detached tabs.
/// Each detached tab gets its own resizable window with the terminal view.
@MainActor
class PopoutWindowController: NSObject, NSWindowDelegate {

    static let shared = PopoutWindowController()

    /// Tracks open pop-out windows so they aren't released prematurely.
    private var windows: [UUID: NSWindow] = [:]
    private var sessions: [UUID: TerminalSession] = [:]
    private var titleObservers: [UUID: AnyCancellable] = [:]

    private override init() {
        super.init()
    }

    /// Creates a new standalone window for the given terminal session.
    func popout(session: TerminalSession) {
        let windowID = session.id

        if let existingWindow = windows[windowID] {
            existingWindow.makeKeyAndOrderFront(nil)
            NSApp.activate(ignoringOtherApps: true)
            return
        }

        let win = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 720, height: 480),
            styleMask: [.titled, .closable, .resizable, .miniaturizable],
            backing: .buffered,
            defer: false
        )
        win.title = session.title
        win.appearance = NSAppearance(named: .darkAqua)
        win.backgroundColor = .black
        win.delegate = self
        win.isReleasedWhenClosed = false

        let hostingView = NSHostingView(
            rootView: SwiftTermView(session: session)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.black)
                .preferredColorScheme(.dark)
        )
        hostingView.frame = NSRect(origin: .zero, size: win.contentRect(forFrameRect: win.frame).size)
        win.contentView = hostingView

        win.center()
        win.makeKeyAndOrderFront(nil)
        NSApp.activate(ignoringOtherApps: true)

        windows[windowID] = win
        sessions[windowID] = session

        // Update window title when the terminal title changes
        titleObservers[windowID] = session.$title
            .receive(on: RunLoop.main)
            .sink { [weak win] title in win?.title = title }
    }

    // MARK: - NSWindowDelegate

    func windowDidBecomeKey(_ notification: Notification) {
        guard let window = notification.object as? NSWindow,
              let entry = windows.first(where: { $0.value === window }),
              let terminalView = sessions[entry.key]?.terminalView,
              terminalView.window === window else { return }

        window.makeFirstResponder(terminalView)
    }

    func windowWillClose(_ notification: Notification) {
        guard let closingWindow = notification.object as? NSWindow else { return }

        // Find which session this window belongs to and clean up
        if let entry = windows.first(where: { $0.value === closingWindow }) {
            sessions[entry.key]?.terminate()
            sessions.removeValue(forKey: entry.key)
            windows.removeValue(forKey: entry.key)
            titleObservers.removeValue(forKey: entry.key)
        }
    }
}
