import CoreGraphics
import Foundation

/// One synthesizable keystroke: a hardware virtual key code plus the modifier flags held around it.
public struct KeyStroke: Equatable, Sendable {
    public let keyCode: CGKeyCode
    public let flags: CGEventFlags
    public init(keyCode: CGKeyCode, flags: CGEventFlags) {
        self.keyCode = keyCode
        self.flags = flags
    }
}

/// Translates the tool-surface chord syntax (`"cmd+s"`, `"return"`, `"cmd+shift+4"`) into a CGEvent
/// keystroke. Pure and unit-tested — the CGEvent posting lives in the agent's input ops.
///
/// Key codes are the ANSI-US hardware codes from Carbon's `Events.h` (`kVK_ANSI_A` …); the VZ guest
/// keyboard is ANSI, so the table is exact for the layouts a guest ships with.
public enum KeyMap {
    /// Parse a chord like `cmd+shift+s` into a keystroke, or `nil` when the (final) key is unknown.
    /// Unknown modifier tokens are ignored (matching the host-side cliclick path's leniency).
    public static func stroke(forChord chord: String) -> KeyStroke? {
        let parts = chord.lowercased().split(separator: "+").map(String.init)
        guard let last = parts.last, let code = keyCodes[normalizeKeyName(last)] else { return nil }
        var flags = CGEventFlags()
        for token in parts.dropLast() {
            if let f = modifierFlags[token] { flags.insert(f) }
        }
        return KeyStroke(keyCode: code, flags: flags)
    }

    /// Alias common key-name spellings to the table's canonical names.
    static func normalizeKeyName(_ key: String) -> String {
        switch key {
        case "enter": return "return"
        case "escape": return "esc"
        case "backspace": return "delete"
        case "arrowup": return "up"
        case "arrowdown": return "down"
        case "arrowleft": return "left"
        case "arrowright": return "right"
        case "spacebar": return "space"
        default: return key
        }
    }

    static let modifierFlags: [String: CGEventFlags] = [
        "cmd": .maskCommand, "command": .maskCommand, "meta": .maskCommand, "super": .maskCommand,
        "ctrl": .maskControl, "control": .maskControl,
        "alt": .maskAlternate, "opt": .maskAlternate, "option": .maskAlternate,
        "shift": .maskShift,
        "fn": .maskSecondaryFn,
    ]

    /// ANSI-US virtual key codes (Carbon `kVK_*`).
    static let keyCodes: [String: CGKeyCode] = [
        "a": 0x00, "s": 0x01, "d": 0x02, "f": 0x03, "h": 0x04, "g": 0x05, "z": 0x06, "x": 0x07,
        "c": 0x08, "v": 0x09, "b": 0x0B, "q": 0x0C, "w": 0x0D, "e": 0x0E, "r": 0x0F, "y": 0x10,
        "t": 0x11, "1": 0x12, "2": 0x13, "3": 0x14, "4": 0x15, "6": 0x16, "5": 0x17, "=": 0x18,
        "9": 0x19, "7": 0x1A, "-": 0x1B, "8": 0x1C, "0": 0x1D, "]": 0x1E, "o": 0x1F, "u": 0x20,
        "[": 0x21, "i": 0x22, "p": 0x23, "l": 0x25, "j": 0x26, "'": 0x27, "k": 0x28, ";": 0x29,
        "\\": 0x2A, ",": 0x2B, "/": 0x2C, "n": 0x2D, "m": 0x2E, ".": 0x2F, "`": 0x32,
        "return": 0x24, "tab": 0x30, "space": 0x31, "delete": 0x33, "esc": 0x35,
        "home": 0x73, "end": 0x77, "pageup": 0x74, "pagedown": 0x79, "forwarddelete": 0x75,
        "left": 0x7B, "right": 0x7C, "down": 0x7D, "up": 0x7E,
        "f1": 0x7A, "f2": 0x78, "f3": 0x63, "f4": 0x76, "f5": 0x60, "f6": 0x61, "f7": 0x62,
        "f8": 0x64, "f9": 0x65, "f10": 0x6D, "f11": 0x67, "f12": 0x6F, "f13": 0x69, "f14": 0x6B,
        "f15": 0x71,
    ]
}
