/**
 * Nut.js Automation Provider
 *
 * Real desktop automation using @nut-tree-fork/nut-js.
 * Provides mouse, keyboard, window, and clipboard control.
 */
// Dynamic imports to avoid loading native modules at startup
let nutjsModule = null;
async function getNutJs() {
    if (!nutjsModule) {
        nutjsModule = await import('@nut-tree-fork/nut-js');
    }
    return nutjsModule;
}
// Key mapping from our KeyCode to nut.js Key enum
const KEY_MAP = {
    // Letters
    a: 'A', b: 'B', c: 'C', d: 'D', e: 'E', f: 'F', g: 'G', h: 'H',
    i: 'I', j: 'J', k: 'K', l: 'L', m: 'M', n: 'N', o: 'O', p: 'P',
    q: 'Q', r: 'R', s: 'S', t: 'T', u: 'U', v: 'V', w: 'W', x: 'X',
    y: 'Y', z: 'Z',
    // Numbers
    '0': 'Num0', '1': 'Num1', '2': 'Num2', '3': 'Num3', '4': 'Num4',
    '5': 'Num5', '6': 'Num6', '7': 'Num7', '8': 'Num8', '9': 'Num9',
    // Function keys
    f1: 'F1', f2: 'F2', f3: 'F3', f4: 'F4', f5: 'F5', f6: 'F6',
    f7: 'F7', f8: 'F8', f9: 'F9', f10: 'F10', f11: 'F11', f12: 'F12',
    // Special keys
    enter: 'Enter', return: 'Return', escape: 'Escape', esc: 'Escape',
    backspace: 'Backspace', tab: 'Tab', space: 'Space',
    up: 'Up', down: 'Down', left: 'Left', right: 'Right',
    home: 'Home', end: 'End', pageup: 'PageUp', pagedown: 'PageDown',
    insert: 'Insert', delete: 'Delete',
    // Modifiers
    ctrl: 'LeftControl', control: 'LeftControl',
    alt: 'LeftAlt', shift: 'LeftShift',
    meta: 'LeftSuper', command: 'LeftSuper', win: 'LeftSuper',
    // Punctuation
    minus: 'Minus', plus: 'Add', equals: 'Equal',
    '[': 'LeftBracket', ']': 'RightBracket',
    ';': 'Semicolon', "'": 'Quote', '`': 'Grave',
    ',': 'Comma', '.': 'Period', '/': 'Slash', '\\': 'Backslash',
};
// Mouse button mapping
const BUTTON_MAP = {
    left: 0,
    right: 1,
    middle: 2,
};
export class NutJsProvider {
    name = 'nutjs';
    capabilities = {
        mouse: true,
        keyboard: true,
        windows: true,
        apps: false, // Limited app control in nut.js
        screenshots: true,
        colorPicker: true,
        clipboard: true,
        ocr: false,
    };
    initialized = false;
    nutjs = null;
    async initialize() {
        try {
            this.nutjs = await getNutJs();
            this.initialized = true;
        }
        catch (error) {
            throw new Error(`Failed to initialize nut.js: ${error}`);
        }
    }
    async shutdown() {
        this.initialized = false;
    }
    async isAvailable() {
        try {
            await getNutJs();
            return true;
        }
        catch {
            return false;
        }
    }
    ensureInitialized() {
        if (!this.initialized || !this.nutjs) {
            throw new Error('NutJsProvider not initialized');
        }
        return this.nutjs;
    }
    getKey(key) {
        const nutjs = this.ensureInitialized();
        const mapped = KEY_MAP[key.toLowerCase()] || key.toUpperCase();
        return nutjs.Key[mapped] ?? nutjs.Key.Space;
    }
    // ============================================================================
    // Mouse Operations
    // ============================================================================
    async getMousePosition() {
        const nutjs = this.ensureInitialized();
        const pos = await nutjs.mouse.getPosition();
        return { x: pos.x, y: pos.y };
    }
    async moveMouse(x, y, options) {
        const nutjs = this.ensureInitialized();
        if (options?.smooth && options.duration) {
            // Smooth movement with duration
            await nutjs.mouse.move(nutjs.straightTo({ x, y }));
        }
        else {
            await nutjs.mouse.setPosition({ x, y });
        }
    }
    async click(options) {
        const nutjs = this.ensureInitialized();
        const button = options?.button
            ? BUTTON_MAP[options.button]
            : nutjs.Button.LEFT;
        const clicks = options?.clicks || 1;
        for (let i = 0; i < clicks; i++) {
            await nutjs.mouse.click(button);
            if (options?.delay && i < clicks - 1) {
                await this.delay(options.delay);
            }
        }
    }
    async doubleClick(button) {
        const nutjs = this.ensureInitialized();
        const btn = button ? BUTTON_MAP[button] : nutjs.Button.LEFT;
        await nutjs.mouse.doubleClick(btn);
    }
    async rightClick() {
        const nutjs = this.ensureInitialized();
        await nutjs.mouse.rightClick();
    }
    async drag(fromX, fromY, toX, toY, _options) {
        const nutjs = this.ensureInitialized();
        await nutjs.mouse.setPosition({ x: fromX, y: fromY });
        await nutjs.mouse.pressButton(nutjs.Button.LEFT);
        await nutjs.mouse.move(nutjs.straightTo({ x: toX, y: toY }));
        await nutjs.mouse.releaseButton(nutjs.Button.LEFT);
    }
    async scroll(options) {
        const nutjs = this.ensureInitialized();
        if (options.deltaY) {
            await nutjs.mouse.scrollDown(Math.abs(options.deltaY));
        }
        if (options.deltaX) {
            // nut.js doesn't have horizontal scroll, simulate with left/right
            // This is a limitation
        }
    }
    // ============================================================================
    // Keyboard Operations
    // ============================================================================
    async keyPress(key, options) {
        const nutjs = this.ensureInitialized();
        const nutKey = this.getKey(key);
        if (options?.modifiers?.length) {
            const modKeys = options.modifiers.map((m) => this.getKey(m));
            await nutjs.keyboard.pressKey(...modKeys);
            await nutjs.keyboard.pressKey(nutKey);
            await nutjs.keyboard.releaseKey(nutKey);
            await nutjs.keyboard.releaseKey(...modKeys);
        }
        else {
            await nutjs.keyboard.pressKey(nutKey);
            if (options?.delay) {
                await this.delay(options.delay);
            }
            await nutjs.keyboard.releaseKey(nutKey);
        }
    }
    async keyDown(key) {
        const nutjs = this.ensureInitialized();
        await nutjs.keyboard.pressKey(this.getKey(key));
    }
    async keyUp(key) {
        const nutjs = this.ensureInitialized();
        await nutjs.keyboard.releaseKey(this.getKey(key));
    }
    async type(text, options) {
        const nutjs = this.ensureInitialized();
        if (options?.delay) {
            // Type character by character with delay
            for (const char of text) {
                await nutjs.keyboard.type(char);
                await this.delay(options.delay + (options.variance ? Math.random() * options.variance : 0));
            }
        }
        else {
            await nutjs.keyboard.type(text);
        }
    }
    async hotkey(sequence) {
        const nutjs = this.ensureInitialized();
        const modKeys = (sequence.modifiers || []).map((m) => this.getKey(m));
        const keys = sequence.keys.map((k) => this.getKey(k));
        // Press modifiers
        for (const mod of modKeys) {
            await nutjs.keyboard.pressKey(mod);
        }
        // Press and release keys
        for (const key of keys) {
            await nutjs.keyboard.pressKey(key);
            await nutjs.keyboard.releaseKey(key);
        }
        // Release modifiers
        for (const mod of modKeys.reverse()) {
            await nutjs.keyboard.releaseKey(mod);
        }
    }
    // ============================================================================
    // Window Operations (Limited in nut.js)
    // ============================================================================
    async getActiveWindow() {
        const nutjs = this.ensureInitialized();
        try {
            const win = await nutjs.getActiveWindow();
            const region = await win.region;
            return {
                handle: String(await win._native.then(n => n.hwnd).catch(() => Math.random())),
                title: await win.title,
                pid: 0, // Not available in nut.js
                processName: '',
                bounds: {
                    x: region.left,
                    y: region.top,
                    width: region.width,
                    height: region.height,
                },
                focused: true,
                visible: true,
                minimized: false,
                maximized: false,
                fullscreen: false,
            };
        }
        catch {
            return null;
        }
    }
    async getWindows(_options) {
        const nutjs = this.ensureInitialized();
        try {
            const windows = await nutjs.getWindows();
            const results = [];
            for (const win of windows) {
                try {
                    const region = await win.region;
                    const title = await win.title;
                    results.push({
                        handle: String(Math.random()),
                        title,
                        pid: 0,
                        processName: '',
                        bounds: {
                            x: region.left,
                            y: region.top,
                            width: region.width,
                            height: region.height,
                        },
                        focused: false,
                        visible: true,
                        minimized: false,
                        maximized: false,
                        fullscreen: false,
                    });
                }
                catch {
                    // Skip windows that can't be queried
                }
            }
            return results;
        }
        catch {
            return [];
        }
    }
    async getWindow(_handle) {
        // nut.js doesn't support getting window by handle
        return null;
    }
    async focusWindow(_handle) {
        // nut.js has limited window focus support
        // Would need to search by title and use focus()
    }
    async minimizeWindow(_handle) {
        // Not directly supported in nut.js
    }
    async maximizeWindow(_handle) {
        // Not directly supported in nut.js
    }
    async restoreWindow(_handle) {
        // Not directly supported in nut.js
    }
    async closeWindow(_handle) {
        // Not directly supported in nut.js
    }
    async setWindow(_handle, _options) {
        // Not directly supported in nut.js
    }
    // ============================================================================
    // Application Operations (Not supported)
    // ============================================================================
    async getRunningApps() {
        return [];
    }
    async launchApp(_appPath, _options) {
        throw new Error('App launching not supported by nut.js provider');
    }
    async closeApp(_pid) {
        throw new Error('App closing not supported by nut.js provider');
    }
    // ============================================================================
    // Screen Operations
    // ============================================================================
    async getScreens() {
        const nutjs = this.ensureInitialized();
        try {
            const screen = await nutjs.screen.width();
            const height = await nutjs.screen.height();
            return [
                {
                    id: 0,
                    name: 'Primary Display',
                    bounds: { x: 0, y: 0, width: screen, height },
                    workArea: { x: 0, y: 0, width: screen, height },
                    scaleFactor: 1,
                    primary: true,
                },
            ];
        }
        catch {
            return [];
        }
    }
    async getPixelColor(x, y) {
        const nutjs = this.ensureInitialized();
        try {
            const color = await nutjs.screen.colorAt({ x, y });
            return {
                r: color.R,
                g: color.G,
                b: color.B,
                a: color.A,
                hex: `#${color.R.toString(16).padStart(2, '0')}${color.G.toString(16).padStart(2, '0')}${color.B.toString(16).padStart(2, '0')}`,
            };
        }
        catch {
            return { r: 0, g: 0, b: 0, hex: '#000000' };
        }
    }
    // ============================================================================
    // Clipboard Operations
    // ============================================================================
    async getClipboard() {
        const nutjs = this.ensureInitialized();
        try {
            const text = await nutjs.clipboard.getContent();
            return {
                text,
                formats: text ? ['text'] : [],
            };
        }
        catch {
            return { formats: [] };
        }
    }
    async setClipboard(content) {
        const nutjs = this.ensureInitialized();
        if (content.text) {
            await nutjs.clipboard.setContent(content.text);
        }
    }
    async clearClipboard() {
        const nutjs = this.ensureInitialized();
        await nutjs.clipboard.setContent('');
    }
    // ============================================================================
    // Helpers
    // ============================================================================
    delay(ms) {
        return new Promise((resolve) => setTimeout(resolve, ms));
    }
}
//# sourceMappingURL=nutjs-provider.js.map