//
//  MSG_DesktopApp.swift
//  MSG Desktop
//
//  Created by Chad Nelson on 3/8/25.
//

import SwiftUI
import AppKit
import Foundation

func runShellCommandAsync(command: String, outputText: Binding<String>?, showButton: Binding<Bool>?) {
    DispatchQueue.global(qos: .background).async {
        let task = Process()
        let pipe = Pipe()
        
        task.standardOutput = pipe
        task.standardError = pipe
        task.arguments = ["-c", command]
        task.launchPath = "/bin/zsh"
        task.standardInput = nil
        
        task.environment = [
            "GUILE_LOAD_PATH": "/opt/homebrew/share/guile/site/3.0:/usr/local/share/guile/site/3.0/",
            "GUILE_LOAD_COMPILED_PATH": "/opt/homebrew/lib/guile/3.0/site-ccache:/usr/local/lib/guile/3.0/site-ccache/",
            "GUILE_SYSTEM_EXTENSIONS_PATH": "/opt/homebrew/lib/guile/3.0/extensions:/usr/local/lib/guile/3.0/extensions/",
            "PATH": "$PATH:/opt/homebrew/bin:/usr/bin:/usr/local/bin:/bin"
        ]
        
        task.launch()
        
        let fileHandle = pipe.fileHandleForReading
        fileHandle.waitForDataInBackgroundAndNotify()
        
        var observer: NSObjectProtocol?
        
        observer = NotificationCenter.default.addObserver(forName: .NSFileHandleDataAvailable, object: fileHandle, queue: nil) { _ in
            let data = fileHandle.availableData
            if let output = String(data: data, encoding: .utf8), !output.isEmpty {
                DispatchQueue.main.async {
                    if let outputText = outputText {
                        outputText.wrappedValue += output
                    }
                }
            }
            fileHandle.waitForDataInBackgroundAndNotify()
        }
        
        task.waitUntilExit()
        
        if let observer = observer {
            NotificationCenter.default.removeObserver(observer)
        }
        
        if showButton != nil {
            showButton?.wrappedValue = false;
        }
    }
}

class AppDelegate: NSObject, NSApplicationDelegate {
    var window: NSWindow!
    
    func applicationWillTerminate(_ notification: Notification) {
        runShellCommandAsync(command: "msg machine stop", outputText: nil, showButton: nil)
        runShellCommandAsync(command: "kill $(ps aux | grep '[g]uile' | awk '{print $2}')", outputText: nil, showButton: nil)
        runShellCommandAsync(command: "kill $(ps aux | grep '[q]emu' | awk '{print $2}')", outputText: nil, showButton: nil)
    }
    
    func saveAppState() {
        print("App is terminating. Saving state...")
        UserDefaults.standard.set(Date(), forKey: "lastClosed")
    }
    
    var statusBarItem: NSStatusItem!
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        
        let contentView = ContentView()
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 800, height: 600),
            styleMask: [.titled, .closable, .resizable, .miniaturizable],
            backing: .buffered,
            defer: false
        )
        window.center()
        //window.setFrameAutosaveName("MSG App")   // to retain size after quitting
        window.contentView = NSHostingView(rootView: contentView)
        window.makeKeyAndOrderFront(nil)
        
        if let button = statusBarItem.button {
            button.title = "MSG"
            button.toolTip = "MSG App"
        }
        
        let menu = NSMenu()
        
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApp), keyEquivalent: "q"))
        
        statusBarItem.menu = menu
    }
    
    @objc func quitApp() {
        let alert = NSAlert()
        alert.messageText = "Are you sure you want to quit?"
        alert.informativeText = "Do you want to quit the app and exit?"
        alert.alertStyle = .warning
        
        alert.addButton(withTitle: "Quit")
        alert.addButton(withTitle: "Cancel")
        
        let response = alert.runModal()
        
        if response == .alertFirstButtonReturn {
            NSApplication.shared.terminate(nil)
        }
    }
    
}

class AppState: ObservableObject {
    @Published var output: String = "Please select an option \n"
    
    static let shared = AppState()
}

@main
struct MSG_DesktopApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        Settings {} // prevents crash on some macOS version
    }
}
