#!/usr/bin/env node
//
// TODO: Migrate to use @bobfrankston/msgcommon for argument parsing
// Example:
//   import { parseCommonArgs } from '@bobfrankston/msgcommon';
//   const { options, messageWords, showHelp, showVersion } = parseCommonArgs(args);
//
import { showMessageBox } from './shower.js';
import packageJson from './package.json' with { type: 'json' };
import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
import JSON5 from 'json5';
// Uncomment when ready to migrate:
// import { parseCommonArgs } from '@bobfrankston/msgcommon';
export default async function main() {
    const args = process.argv.slice(2);
    // No arguments - show help
    if (args.length === 0) {
        showHelp();
        process.exit(0);
    }
    // Parse command line arguments
    let options, shouldShowHelp, shouldShowVersion, loadFile, saveFile, noshow, shouldPin;
    try {
        ({ options, showHelp: shouldShowHelp, showVersion: shouldShowVersion, loadFile, saveFile, noshow, pin: shouldPin } = parseCliArgs(args));
    }
    catch (error) {
        console.error('Error:', error.message);
        console.error('\nUse -help to see usage information.');
        process.exit(1);
    }
    // Helper to add .json extension if no extension specified
    const ensureJsonExt = (filename) => {
        const ext = path.extname(filename);
        return ext ? filename : `${filename}.json`;
    };
    // Handle -pin: create pinnable shortcut (Windows only)
    if (shouldPin) {
        console.error('Error: -pin is not yet implemented');
        console.error('Taskbar pinning requires packaged .exe files, not Node.js scripts');
        console.error('This feature will be available once msger is packaged as a standalone executable');
        process.exit(1);
    }
    // Load config file if specified
    let finalOptions = options;
    if (loadFile) {
        try {
            const loadedConfig = loadConfigFile(ensureJsonExt(loadFile));
            finalOptions = { ...loadedConfig };
            if (options.title)
                finalOptions.title = options.title;
            if (options.message)
                finalOptions.message = options.message;
            if (options.html)
                finalOptions.html = options.html;
            if (options.url)
                finalOptions.url = options.url;
            if (options.hash)
                finalOptions.hash = options.hash;
            if (options.size)
                finalOptions.size = options.size;
            if (options.pos)
                finalOptions.pos = options.pos;
            if (options.buttons && options.buttons.length > 0)
                finalOptions.buttons = options.buttons;
            if (options.allowInput !== undefined)
                finalOptions.allowInput = options.allowInput;
            if (options.defaultValue)
                finalOptions.defaultValue = options.defaultValue;
            if (options.inputPlaceholder)
                finalOptions.inputPlaceholder = options.inputPlaceholder;
            if (options.timeout !== undefined)
                finalOptions.timeout = options.timeout;
            if (options.alwaysOnTop !== undefined)
                finalOptions.alwaysOnTop = options.alwaysOnTop;
            if (options.fullscreen !== undefined)
                finalOptions.fullscreen = options.fullscreen;
            if (options.zoom !== undefined)
                finalOptions.zoom = options.zoom;
            if (options.icon)
                finalOptions.icon = options.icon;
            if (options.dev !== undefined)
                finalOptions.dev = options.dev;
            if (options.debug !== undefined)
                finalOptions.debug = options.debug;
            if (options.detach !== undefined)
                finalOptions.detach = options.detach;
            // Generate AppUserModelID for pinning support
            if (process.platform === 'win32') {
                try {
                    const { getAppUserModelIdForConfig } = await import('@bobfrankston/msgcommon/pinning');
                    const appId = getAppUserModelIdForConfig('msger', path.resolve(ensureJsonExt(loadFile)));
                    if (appId) {
                        finalOptions.appUserModelId = appId;
                    }
                }
                catch (error) {
                    // Silently ignore if msgcommon is not available
                }
            }
        }
        catch (error) {
            console.error('Error loading config:', error.message);
            process.exit(1);
        }
    }
    if (!finalOptions.buttons || finalOptions.buttons.length === 0) {
        finalOptions.buttons = ['OK'];
    }
    // Help always takes precedence and exits
    if (shouldShowHelp) {
        showHelp();
        process.exit(0);
    }
    // Version only exits if there's nothing else meaningful to do
    // (no actual message/url/html content was provided - the default message doesn't count)
    const hasRealContent = args.some(arg => !arg.startsWith('-') ||
        arg === '-message' ||
        arg === '-html' ||
        arg === '-url');
    if (shouldShowVersion && !hasRealContent) {
        showVersion();
        process.exit(0);
    }
    // If version was requested along with other options, add it to title
    if (shouldShowVersion && hasRealContent) {
        finalOptions.showVersion = true;
    }
    if (saveFile) {
        try {
            let saveFilePath;
            if (saveFile === true) {
                if (!loadFile) {
                    console.error('Error: -save without filename requires -load to be specified');
                    process.exit(1);
                }
                saveFilePath = ensureJsonExt(loadFile);
            }
            else {
                saveFilePath = ensureJsonExt(saveFile);
            }
            const toSave = saveFile === true ? finalOptions : options;
            saveConfigFile(saveFilePath, toSave);
            console.log(`Configuration saved to: ${saveFilePath}`);
            if (noshow) {
                process.exit(0);
            }
            if (!finalOptions.message && !finalOptions.url && !finalOptions.html) {
                process.exit(0);
            }
        }
        catch (error) {
            console.error('Error saving config:', error.message);
            process.exit(1);
        }
    }
    // If no actual message/content was provided, show help
    if (!finalOptions.message && !finalOptions.url && !finalOptions.html) {
        showHelp();
        process.exit(0);
    }
    try {
        const result = await showMessageBox(finalOptions);
        // If detached, exit immediately without printing result
        if (finalOptions.detach) {
            process.exit(0);
        }
        console.log(JSON.stringify(result, null, 2));
        // Exit with code based on result
        if (result.dismissed || result.closed) {
            process.exit(1);
        }
    }
    catch (error) {
        console.error('Error:', error.message);
        process.exit(1);
    }
}
const HELP_TEXT = `
msger v${packageJson.version} - Fast, lightweight, cross-platform message box (Rust-powered)

Usage:
  msger [options] [message words...]
  msger -message "Your message"
  echo '{"message":"text"}' | msger

Options:
  -message <text>         Specify message text (use quotes for multi-word)
                          Supports ANSI color escape sequences (e.g., \\x1b[31mRed\\x1b[0m)
  -title <text>           Set window title
  -html <html>            Display HTML formatted message (inline)
  -htmlfrom <file|url>    Fetch HTML from file/URL and embed in template (has buttons & msger API)
  -url <url>              Load URL directly in webview (no template, no buttons)
  -hash <fragment>        Hash fragment to append to URL (requires -url). Leading # optional.
  -buttons <label...>     Specify button labels (e.g., -buttons Yes No Cancel)
  -ok                     Add OK button
  -cancel                 Add Cancel button
  -input [placeholder]    Include an input field with optional placeholder text
  -default <text>         Default value for input field
  -size <width,height>    Set window size (e.g., -size 800,600)
  -zoom <percent>         Set zoom level as percentage (e.g., -zoom 150 for 150%)
  -pos <x,y>              Set window position (e.g., -pos 100,200)
  -screen <number>        [Windows only] Screen index for multi-monitor (0=primary, 1=second, etc.)
  -icon <path>            Set window icon (PNG file). Default: icon.png in current directory
  -timeout <seconds>      Auto-close after specified seconds
  -detach                 Leave window open after app exits (parent process returns immediately)
  -fullscreen             Start window in fullscreen mode (F11 to toggle, Escape to exit)
  -no-escape-closes       Prevent Escape key from closing window (still exits fullscreen)
  -reset                  Clear localStorage on startup (useful for resetting web content state)
  -ontop                  Keep window always on top of other windows
  -load <file>            Load options from JSON file (supports comments)
  -save <file>            Save current options to JSON file
  -noshow                 Save config without showing message box (use with -save)
  -pin                    [Not yet implemented] Create pinnable taskbar shortcut
  -dev                    Open DevTools (F12) automatically on startup (for debugging)
  -debug                  Return debug info (HTML, size) in result
  -v, -version, --version Show version number (alone: print and exit; with options: show in title)
  -help, -?, --help       Show this help message

Examples:
  msger Hello World
  msger -message "Save changes?" -buttons Yes No Cancel
  msger -message "Enter your name:" -input "Your name" -default "John Doe"
  msger -html "<h1>Title</h1><p>Formatted content</p>"
  msger -htmlfrom page.html -buttons OK Cancel
  msger -htmlfrom "https://example.com" -buttons OK
  msger -url "https://example.com"
  msger -url "https://example.com" -hash section1
  msger -url "https://example.com" -detach
  msger -title "Alert" -message "Operation complete"
  echo -e "\\x1b[31mError:\\x1b[0m Something failed" | msger
  echo '{"message":"Test","buttons":["OK"]}' | msger

Notes:
  - If no options are provided, all non-option arguments are concatenated as the message
  - Message text supports ANSI color codes (automatically converted to HTML)
  - Press ESC to dismiss the dialog (returns button: "dismissed")
  - Press Enter to click the last (default) button
  - Default button is OK if no buttons specified
  - Much faster than Electron-based msgview (~50-200ms vs ~2-3s startup)

Security Note:
  - msger is designed for displaying trusted, friendly content (local apps, your own HTML)
  - It is NOT a secure sandbox for untrusted/hostile web content
  - Use -htmlfrom and -url with trusted sources only
`;
function parseCliArgs(args) {
    const cli = {
        buttons: [],
        input: false,
        help: false
    };
    let i = 0;
    const messageWords = [];
    while (i < args.length) {
        const arg = args[i];
        if (arg === '-help' || arg === '--help' || arg === '-?' || arg === '/?') {
            cli.help = true;
            i++;
        }
        else if (arg === '-v' || arg === '-version' || arg === '--version') {
            cli.version = true;
            i++;
        }
        else if (arg === '-message' || arg === '--message') {
            if (i + 1 >= args.length) {
                throw new Error('-message requires a text argument');
            }
            cli.message = args[++i];
            i++;
        }
        else if (arg === '-title' || arg === '--title') {
            if (i + 1 >= args.length) {
                throw new Error('-title requires a text argument');
            }
            cli.title = args[++i];
            i++;
        }
        else if (arg === '-html' || arg === '--html') {
            if (i + 1 >= args.length) {
                throw new Error('-html requires an HTML string argument');
            }
            cli.html = args[++i];
            i++;
        }
        else if (arg === '-htmlfrom' || arg === '--htmlfrom') {
            if (i + 1 >= args.length) {
                throw new Error('-htmlfrom requires a file path or URL argument');
            }
            cli.htmlFrom = args[++i];
            i++;
        }
        else if (arg === '-url' || arg === '--url') {
            if (i + 1 >= args.length) {
                throw new Error('-url requires a URL argument');
            }
            cli.url = args[++i];
            i++;
        }
        else if (arg === '-hash' || arg === '--hash') {
            if (i + 1 >= args.length) {
                throw new Error('-hash requires a fragment argument');
            }
            cli.hash = args[++i];
            i++;
        }
        else if (arg === '-buttons' || arg === '--buttons') {
            i++;
            while (i < args.length && !args[i].startsWith('-')) {
                cli.buttons.push(args[i]);
                i++;
            }
        }
        else if (arg === '-ok' || arg === '--ok') {
            if (!cli.buttons.includes('OK')) {
                cli.buttons.push('OK');
            }
            i++;
        }
        else if (arg === '-cancel' || arg === '--cancel') {
            if (!cli.buttons.includes('Cancel')) {
                cli.buttons.push('Cancel');
            }
            i++;
        }
        else if (arg === '-input' || arg === '--input') {
            cli.input = true;
            if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
                cli.inputPlaceholder = args[++i];
            }
            i++;
        }
        else if (arg === '-default' || arg === '--default') {
            if (i + 1 >= args.length) {
                throw new Error('-default requires a text argument');
            }
            cli.defaultValue = args[++i];
            i++;
        }
        else if (arg === '-timeout' || arg === '--timeout') {
            if (i + 1 >= args.length) {
                throw new Error('-timeout requires a number argument');
            }
            cli.timeout = parseInt(args[++i], 10);
            i++;
        }
        else if (arg === '-detach' || arg === '--detach') {
            cli.detach = true;
            i++;
        }
        else if (arg === '-fullscreen' || arg === '--fullscreen') {
            cli.fullscreen = true;
            i++;
        }
        else if (arg === '-full' || arg === '--full') {
            cli.full = true;
            i++;
        }
        else if (arg === '-no-escape-closes' || arg === '--no-escape-closes') {
            cli.escapeCloses = false;
            i++;
        }
        else if (arg === '-reset' || arg === '--reset') {
            cli.reset = true;
            i++;
        }
        else if (arg === '-ontop' || arg === '--ontop' || arg === '-alwaysontop' || arg === '--alwaysontop') {
            cli.alwaysOnTop = true;
            i++;
        }
        else if (arg === '-size' || arg === '--size') {
            if (i + 1 >= args.length) {
                throw new Error('-size requires a width,height argument');
            }
            const size = args[++i];
            const [w, h] = size.split(',').map(s => parseInt(s.trim(), 10));
            if (w)
                cli.width = w;
            if (h)
                cli.height = h;
            i++;
        }
        else if (arg === '-zoom' || arg === '--zoom') {
            if (i + 1 >= args.length) {
                throw new Error('-zoom requires a percentage argument');
            }
            cli.zoom = parseFloat(args[++i]);
            i++;
        }
        else if (arg === '-pos' || arg === '--pos') {
            if (i + 1 >= args.length) {
                throw new Error('-pos requires an x,y or x,y,screen argument');
            }
            const pos = args[++i];
            const parts = pos.split(',').map(s => parseInt(s.trim(), 10));
            if (!isNaN(parts[0]))
                cli.posX = parts[0];
            if (!isNaN(parts[1]))
                cli.posY = parts[1];
            if (!isNaN(parts[2]))
                cli.screen = parts[2];
            i++;
        }
        else if (arg === '-screen' || arg === '--screen') {
            if (i + 1 >= args.length) {
                throw new Error('-screen requires a number argument');
            }
            cli.screen = parseInt(args[++i], 10);
            i++;
        }
        else if (arg === '-icon' || arg === '--icon') {
            if (i + 1 >= args.length) {
                throw new Error('-icon requires a file path argument');
            }
            cli.icon = args[++i];
            i++;
        }
        else if (arg === '-dev' || arg === '--dev') {
            cli.dev = true;
            i++;
        }
        else if (arg === '-debug' || arg === '--debug') {
            cli.debug = true;
            i++;
        }
        else if (arg === '-load' || arg === '--load') {
            if (i + 1 >= args.length) {
                throw new Error('-load requires a file path argument');
            }
            cli.load = args[++i];
            i++;
        }
        else if (arg === '-save' || arg === '--save') {
            const nextArg = args[i + 1];
            if (nextArg && !nextArg.startsWith('-')) {
                cli.save = nextArg;
                i += 2;
            }
            else {
                cli.save = true;
                i++;
            }
        }
        else if (arg === '-noshow' || arg === '--noshow') {
            cli.noshow = true;
            i++;
        }
        else if (arg === '-pin' || arg === '--pin') {
            cli.pin = true;
            i++;
        }
        else if (!arg.startsWith('-')) {
            messageWords.push(arg);
            i++;
        }
        else {
            console.warn(`Unknown option: ${arg}`);
            i++;
        }
    }
    if (cli.full && cli.url) {
        throw new Error('-full and -url cannot be used together. Did you mean -fullscreen?');
    }
    let message;
    let html;
    let url;
    if (cli.url) {
        message = cli.url;
        url = cli.url;
    }
    else if (cli.htmlFrom) {
        if (cli.htmlFrom.startsWith('http://') || cli.htmlFrom.startsWith('https://')) {
            try {
                const fetchCommand = `node --input-type=module -e "const res = await fetch('${cli.htmlFrom}'); console.log(await res.text())"`;
                const htmlContent = execSync(fetchCommand, { encoding: 'utf-8' });
                message = htmlContent;
                html = htmlContent;
            }
            catch (error) {
                throw new Error(`Failed to fetch HTML from URL: ${error.message}`);
            }
        }
        else {
            const htmlPath = path.resolve(cli.htmlFrom);
            if (!fs.existsSync(htmlPath)) {
                throw new Error(`HTML file not found: ${htmlPath}`);
            }
            try {
                const htmlContent = fs.readFileSync(htmlPath, 'utf-8');
                message = htmlContent;
                html = htmlContent;
            }
            catch (error) {
                throw new Error(`Failed to read HTML file: ${error.message}`);
            }
        }
    }
    else if (cli.html) {
        message = cli.html;
        html = cli.html;
    }
    else if (cli.message) {
        message = cli.message;
    }
    else if (messageWords.length > 0) {
        message = messageWords.join(' ');
    }
    else {
        message = '';
    }
    const options = {
        title: cli.title,
        message,
        html,
        url,
        hash: cli.hash,
        buttons: cli.buttons,
        allowInput: cli.input,
        defaultValue: cli.defaultValue,
        inputPlaceholder: cli.inputPlaceholder,
        timeout: cli.timeout,
        detach: cli.detach,
        fullscreen: cli.fullscreen,
        alwaysOnTop: cli.alwaysOnTop,
        zoom: cli.zoom,
        icon: cli.icon,
        dev: cli.dev,
        debug: cli.debug
    };
    if (cli.width !== undefined || cli.height !== undefined) {
        const defaultWidth = url ? 1024 : 600;
        const defaultHeight = url ? 768 : 400;
        options.size = {
            width: cli.width !== undefined ? cli.width : defaultWidth,
            height: cli.height !== undefined ? cli.height : defaultHeight,
        };
    }
    else if (url) {
        options.size = {
            width: 1024,
            height: 768,
        };
    }
    if (cli.posX !== undefined && cli.posY !== undefined) {
        options.pos = { x: cli.posX, y: cli.posY };
        if (cli.screen !== undefined) {
            options.pos.screen = cli.screen;
        }
    }
    return {
        options,
        showHelp: cli.help || false,
        showVersion: cli.version || false,
        loadFile: cli.load,
        saveFile: cli.save,
        noshow: cli.noshow || false,
        pin: cli.pin || false
    };
}
function loadConfigFile(filePath) {
    const absolutePath = path.resolve(filePath);
    if (!fs.existsSync(absolutePath)) {
        throw new Error(`Config file not found: ${absolutePath}`);
    }
    const fileContent = fs.readFileSync(absolutePath, 'utf-8');
    try {
        const config = JSON5.parse(fileContent);
        if (config.pos && typeof config.pos === 'string') {
            const parts = config.pos.split(',').map((s) => parseInt(s.trim(), 10));
            const posObj = { x: parts[0], y: parts[1] };
            if (!isNaN(parts[2])) {
                posObj.screen = parts[2];
            }
            config.pos = posObj;
        }
        // Resolve icon path relative to JSON directory
        if (config.icon && !path.isAbsolute(config.icon)) {
            const jsonDir = path.dirname(absolutePath);
            config.icon = path.resolve(jsonDir, config.icon);
        }
        return config;
    }
    catch (error) {
        throw new Error(`Failed to parse config file ${filePath}: ${error.message}`);
    }
}
function saveConfigFile(filePath, options) {
    const absolutePath = path.resolve(filePath);
    const config = {};
    if (options.title && options.title !== 'Message')
        config.title = options.title;
    if (options.message)
        config.message = options.message;
    if (options.html)
        config.html = options.html;
    // Save URL without hash fragment (hash is specified via -hash option)
    if (options.url)
        config.url = options.url.split('#')[0];
    if (options.hash)
        config.hash = options.hash;
    if (options.size)
        config.size = options.size;
    if (options.pos) {
        config.pos = { x: options.pos.x, y: options.pos.y };
        if (options.pos.screen !== undefined) {
            config.pos.screen = options.pos.screen;
        }
    }
    if (options.buttons && options.buttons.length > 0 && JSON.stringify(options.buttons) !== '["OK"]') {
        config.buttons = options.buttons;
    }
    if (options.allowInput)
        config.allowInput = options.allowInput;
    if (options.defaultValue)
        config.defaultValue = options.defaultValue;
    if (options.inputPlaceholder)
        config.inputPlaceholder = options.inputPlaceholder;
    if (options.timeout)
        config.timeout = options.timeout;
    if (options.alwaysOnTop)
        config.alwaysOnTop = options.alwaysOnTop;
    if (options.fullscreen)
        config.fullscreen = options.fullscreen;
    if (options.zoom && options.zoom !== 100)
        config.zoom = options.zoom;
    if (options.icon)
        config.icon = options.icon;
    if (options.dev)
        config.dev = options.dev;
    if (options.debug)
        config.debug = options.debug;
    const jsonContent = JSON.stringify(config, null, 4) + '\n';
    fs.writeFileSync(absolutePath, jsonContent, 'utf-8');
}
function showHelp() {
    console.log(HELP_TEXT);
}
function showVersion() {
    console.log(packageJson.version);
}
// Run main when file is executed (either directly or as a bin script)
if (import.meta.main) {
    await main();
}
