"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
const node_path_1 = require("node:path");
const node_fs_1 = require("node:fs");
const node_os_1 = require("node:os");
const node_module_1 = require("node:module");
const data_1 = require("./data");
const ui_1 = require("./ui");
const nodeRequire = (0, node_module_1.createRequire)(__filename);
const Database = nodeRequire('better-sqlite3');
const DB_PATH = (0, node_path_1.join)((0, node_os_1.homedir)(), '.aiusage', 'cache.db');
const PORT_FILE = (0, node_path_1.join)((0, node_os_1.homedir)(), '.aiusage', '.serve-port');
const DASHBOARD_PORT = 3847;
const REFRESH_INTERVAL_MS = 60000;
let tray = null;
let win = null;
let db = null;
electron_1.app.setName('aiusage Widget');
// Prevent dock icon on macOS
if (process.platform === 'darwin' && electron_1.app.dock) {
    electron_1.app.dock.hide();
}
electron_1.app.whenReady().then(() => {
    if ((0, node_fs_1.existsSync)(DB_PATH)) {
        db = new Database(DB_PATH, {
            readonly: true,
            nativeBinding: (0, ui_1.getWidgetNativeBindingPath)(__dirname),
        });
    }
    createTray();
    createWindow();
    startAutoRefresh();
    if ((0, ui_1.shouldShowWindowOnLaunch)(electron_1.app.isPackaged)) {
        showWindow();
    }
});
electron_1.app.on('window-all-closed', () => {
    // Keep the app running in the tray — do not quit
});
electron_1.app.on('before-quit', () => {
    db?.close();
});
function createTray() {
    const { buffer, scaleFactor } = (0, ui_1.getTrayIconNativeImage)();
    const icon = electron_1.nativeImage.createFromBuffer(buffer, scaleFactor ? { scaleFactor } : undefined);
    tray = new electron_1.Tray(icon);
    tray.setToolTip('aiusage Widget');
    tray.on('click', () => toggleWindow());
    tray.on('right-click', () => {
        const menu = electron_1.Menu.buildFromTemplate([
            { label: 'Show Panel', click: () => showWindow() },
            { label: 'Refresh', click: () => pushDataUpdate() },
            { type: 'separator' },
            { label: 'Quit', click: () => { electron_1.app.exit(0); } },
        ]);
        tray.popUpContextMenu(menu);
    });
}
function createWindow() {
    win = new electron_1.BrowserWindow({
        width: 320,
        height: 300,
        show: false,
        frame: false,
        resizable: false,
        skipTaskbar: true,
        alwaysOnTop: true,
        transparent: true,
        webPreferences: {
            preload: (0, node_path_1.join)(__dirname, 'preload.js'),
            contextIsolation: true,
            nodeIntegration: false,
        },
    });
    const rendererPath = (0, node_path_1.join)(__dirname, 'renderer', 'index.html');
    win.loadFile(rendererPath);
    if ((0, ui_1.shouldHideWindowOnBlur)(electron_1.app.isPackaged)) {
        win.on('blur', () => win?.hide());
    }
}
function showWindow() {
    if (!win)
        return;
    // Position near tray icon
    const trayBounds = tray.getBounds();
    const winBounds = win.getBounds();
    const displayBounds = electron_1.screen.getDisplayNearestPoint({ x: trayBounds.x, y: trayBounds.y }).workArea;
    const { x, y } = (0, ui_1.getWindowPosition)({
        platform: process.platform,
        trayBounds,
        windowBounds: winBounds,
        displayBounds,
    });
    win.setPosition(x, y, false);
    win.show();
    win.focus();
    pushDataUpdate();
}
function toggleWindow() {
    if (win?.isVisible()) {
        win.hide();
    }
    else {
        showWindow();
    }
}
function pushDataUpdate() {
    if (!win || !db)
        return;
    try {
        const data = (0, data_1.queryWidgetData)(db);
        win.webContents.send('widget:data-update', data);
    }
    catch {
        // DB may not be initialized yet; silently skip
    }
}
function startAutoRefresh() {
    setInterval(() => pushDataUpdate(), REFRESH_INTERVAL_MS);
}
// IPC handlers
electron_1.ipcMain.handle('widget:get-data', () => {
    if (!db)
        return null;
    return (0, data_1.queryWidgetData)(db);
});
electron_1.ipcMain.handle('widget:open-dashboard', async () => {
    const port = getDashboardPort();
    const reachable = await isDashboardReachable(port);
    if (!reachable) {
        const result = await launchDashboard();
        if (!result.success) {
            electron_1.dialog.showErrorBox('aiusage Not Found', 'The aiusage CLI is not installed.\n\nInstall it with:\n  npm install -g @juliantanx/aiusage\n\nThen try again.');
            return;
        }
    }
    electron_1.shell.openExternal(`http://localhost:${getDashboardPort()}`);
});
electron_1.ipcMain.on('widget:hide-window', () => {
    win?.hide();
});
function getDashboardPort() {
    try {
        if ((0, node_fs_1.existsSync)(PORT_FILE)) {
            const port = parseInt((0, node_fs_1.readFileSync)(PORT_FILE, 'utf-8').trim(), 10);
            if (!isNaN(port) && port > 0)
                return port;
        }
    }
    catch { }
    return DASHBOARD_PORT;
}
async function isDashboardReachable(port) {
    return new Promise((resolve) => {
        const http = nodeRequire('http');
        const req = http.get(`http://localhost:${port}`, (res) => {
            res.destroy();
            resolve(res.statusCode !== undefined && res.statusCode < 500);
        });
        req.on('error', () => resolve(false));
        // 200ms is plenty for localhost; 1000ms caused each poll to block for 1s
        req.setTimeout(200, () => { req.destroy(); resolve(false); });
    });
}
async function launchDashboard() {
    const { spawn } = nodeRequire('child_process');
    return new Promise((resolve) => {
        const child = spawn('aiusage', ['serve'], {
            detached: true,
            stdio: 'ignore',
            shell: true,
        });
        let failed = false;
        child.on('error', () => { failed = true; });
        // shell:true suppresses ENOENT on the error event — the shell itself spawns fine
        // but exits immediately (code 127) when the command isn't found. Detect that here.
        child.on('close', (code) => {
            if (code !== 0)
                failed = true;
        });
        child.unref();
        // Poll up to 5s (25 × 200ms) for the server to become reachable
        let attempts = 0;
        const check = async () => {
            if (failed) {
                resolve({ success: false, error: 'aiusage command not found' });
                return;
            }
            if (await isDashboardReachable(getDashboardPort())) {
                resolve({ success: true });
                return;
            }
            attempts++;
            if (attempts >= 25) {
                resolve({ success: false, error: 'Server failed to start within 5 seconds' });
                return;
            }
            setTimeout(check, 200);
        };
        check();
    });
}
