import SwiftUI
import SwiftTerm
import AppKit

// Helper to create SwiftTerm Color from hex
extension SwiftTerm.Color {
    convenience init(hex: String) {
        var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
        hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")

        var rgb: UInt64 = 0
        Scanner(string: hexSanitized).scanHexInt64(&rgb)

        let r = UInt16((rgb & 0xFF0000) >> 16)
        let g = UInt16((rgb & 0x00FF00) >> 8)
        let b = UInt16(rgb & 0x0000FF)

        // Convert 8-bit to 16-bit
        self.init(red: r * 257, green: g * 257, blue: b * 257)
    }
}

struct TerminalContainerView: View {
    @ObservedObject var tab: Tab
    let config: GhosttyConfig

    init(tab: Tab, config: GhosttyConfig = GhosttyConfig.load()) {
        self.tab = tab
        self.config = config
    }

    var body: some View {
        SwiftTermView(tab: tab, config: config)
            .background(Color(config.backgroundColor))
    }
}

// Custom wrapper to handle first responder and layout
class FocusableTerminalView: NSView {
    var terminalView: LocalProcessTerminalView?
    private var scroller: NSScroller?
    private var fadeTimer: Timer?
    private var scrollMonitor: Any?
    private var lastScrollerValue: Double = 0

    override var acceptsFirstResponder: Bool { true }

    override func becomeFirstResponder() -> Bool {
        if let tv = terminalView {
            DispatchQueue.main.async {
                self.window?.makeFirstResponder(tv)
            }
        }
        return true
    }

    override func mouseDown(with event: NSEvent) {
        window?.makeFirstResponder(terminalView)
        super.mouseDown(with: event)
    }

    override func layout() {
        super.layout()
        if let tv = terminalView, bounds.size.width > 0, bounds.size.height > 0 {
            tv.setFrameSize(bounds.size)
            setupScrollerTracking(in: tv)
        }
    }

    override func viewDidMoveToWindow() {
        super.viewDidMoveToWindow()
        if window != nil, let tv = terminalView, bounds.size.width > 0 {
            tv.setFrameSize(bounds.size)
            setupScrollerTracking(in: tv)
            setupScrollMonitor()
        }
    }

    override func viewWillMove(toWindow newWindow: NSWindow?) {
        super.viewWillMove(toWindow: newWindow)
        if newWindow == nil, let monitor = scrollMonitor {
            NSEvent.removeMonitor(monitor)
            scrollMonitor = nil
        }
    }

    private func setupScrollerTracking(in view: NSView) {
        if scroller == nil {
            for subview in view.subviews {
                if let s = subview as? NSScroller {
                    scroller = s
                    s.alphaValue = 0  // Start hidden
                    lastScrollerValue = s.doubleValue
                    break
                }
            }
        }
    }

    private func setupScrollMonitor() {
        guard scrollMonitor == nil else { return }

        // Monitor scroll wheel events
        scrollMonitor = NSEvent.addLocalMonitorForEvents(matching: .scrollWheel) { [weak self] event in
            if let self = self,
               let window = self.window,
               event.window == window {
                self.showScrollerTemporarily()
            }
            return event
        }
    }

    func showScrollerTemporarily() {
        guard let scroller = scroller else { return }

        // Show scroller
        NSAnimationContext.runAnimationGroup { context in
            context.duration = 0.15
            scroller.animator().alphaValue = 1
        }

        // Cancel existing timer
        fadeTimer?.invalidate()

        // Fade out after 1.5 seconds of no scrolling
        fadeTimer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false) { [weak self] _ in
            NSAnimationContext.runAnimationGroup { context in
                context.duration = 0.3
                self?.scroller?.animator().alphaValue = 0
            }
        }
    }
}

struct SwiftTermView: NSViewRepresentable {
    @ObservedObject var tab: Tab
    let config: GhosttyConfig

    func makeNSView(context: Context) -> FocusableTerminalView {
        let containerView = FocusableTerminalView()
        containerView.wantsLayer = true

        let terminalView = LocalProcessTerminalView(frame: CGRect(x: 0, y: 0, width: 800, height: 600))

        // Use autoresizingMask instead of Auto Layout for SwiftTerm compatibility
        terminalView.autoresizingMask = [.width, .height]

        // Apply Ghostty config colors
        terminalView.nativeForegroundColor = config.foregroundColor
        terminalView.nativeBackgroundColor = config.backgroundColor

        // Set cursor color to match Ghostty
        terminalView.caretColor = config.cursorColor
        terminalView.caretTextColor = config.cursorTextColor

        // Set selection colors
        terminalView.selectedTextBackgroundColor = config.selectionBackground

        // Apply ANSI palette colors
        applyPalette(to: terminalView, config: config)

        // Configure font from config
        if let font = NSFont(name: config.fontFamily, size: config.fontSize) {
            terminalView.font = font
        } else {
            terminalView.font = NSFont.monospacedSystemFont(ofSize: config.fontSize, weight: .regular)
        }

        // Set terminal delegate (only processDelegate, not terminalDelegate which breaks input)
        terminalView.processDelegate = context.coordinator
        context.coordinator.terminalView = terminalView
        context.coordinator.containerView = containerView

        containerView.addSubview(terminalView)
        containerView.terminalView = terminalView

        // Get shell path
        let shell = ProcessInfo.processInfo.environment["SHELL"] ?? "/bin/zsh"

        // Determine working directory
        let workingDir = config.workingDirectory ?? FileManager.default.homeDirectoryForCurrentUser.path

        // Build environment with working directory
        var env = ProcessInfo.processInfo.environment
        env["PWD"] = workingDir

        // Start the shell process
        terminalView.startProcess(
            executable: shell,
            args: [],
            environment: env.map { "\($0.key)=\($0.value)" },
            execName: "-" + (shell as NSString).lastPathComponent
        )

        // Change to working directory
        terminalView.feed(text: "cd \"\(workingDir)\" && clear\n")


        // Make first responder after a delay to ensure window is ready
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            containerView.window?.makeFirstResponder(terminalView)
        }

        return containerView
    }

    func updateNSView(_ nsView: FocusableTerminalView, context: Context) {
        // When this view becomes visible (tab switch), make it first responder
        DispatchQueue.main.async {
            if let terminalView = nsView.terminalView {
                nsView.window?.makeFirstResponder(terminalView)
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(tab: tab)
    }

    private func applyPalette(to terminalView: LocalProcessTerminalView, config: GhosttyConfig) {
        // SwiftTerm uses installColors to set the ANSI color palette
        // Build the color array (16 ANSI colors)

        // Default Monokai Classic palette hex values
        let defaultPaletteHex: [String] = [
            "#272822", // 0 - black
            "#f92672", // 1 - red
            "#a6e22e", // 2 - green
            "#e6db74", // 3 - yellow
            "#fd971f", // 4 - blue (orange in Monokai)
            "#ae81ff", // 5 - magenta
            "#66d9ef", // 6 - cyan
            "#fdfff1", // 7 - white
            "#6e7066", // 8 - bright black
            "#f92672", // 9 - bright red
            "#a6e22e", // 10 - bright green
            "#e6db74", // 11 - bright yellow
            "#fd971f", // 12 - bright blue
            "#ae81ff", // 13 - bright magenta
            "#66d9ef", // 14 - bright cyan
            "#fdfff1", // 15 - bright white
        ]

        var colors: [SwiftTerm.Color] = []
        for i in 0..<16 {
            colors.append(SwiftTerm.Color(hex: defaultPaletteHex[i]))
        }

        // Install the ANSI colors
        terminalView.installColors(colors)
    }

    class Coordinator: NSObject, LocalProcessTerminalViewDelegate {
        var tab: Tab
        weak var terminalView: LocalProcessTerminalView?
        weak var containerView: FocusableTerminalView?

        init(tab: Tab) {
            self.tab = tab
        }

        func sizeChanged(source: LocalProcessTerminalView, newCols: Int, newRows: Int) {
            // Handle size change
        }

        func setTerminalTitle(source: LocalProcessTerminalView, title: String) {
            DispatchQueue.main.async {
                if !title.isEmpty {
                    self.tab.title = title
                }
            }
        }

        func hostCurrentDirectoryUpdate(source: TerminalView, directory: String?) {
            if let dir = directory {
                DispatchQueue.main.async {
                    self.tab.currentDirectory = dir
                }
            }
        }

        func processTerminated(source: TerminalView, exitCode: Int32?) {
            // Could close tab or show message
        }
    }
}
