/**
 * JSON-RPC dispatcher for MailxService.
 * Maps mailxapi action names to MailxService method calls.
 * Used by msger's bidirectional IPC (Phase 3) and can also
 * serve as a stdio JSON-RPC interface for testing.
 */
import { readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const rootPkg = JSON.parse(readFileSync(join(__dirname, "..", "..", "package.json"), "utf-8"));
/** Dispatch an incoming mailxapi call to the appropriate MailxService method */
export async function dispatch(svc, req) {
    const { _action, _cbid, ...params } = req;
    try {
        const result = await dispatchAction(svc, _action, params);
        return { _cbid, result };
    }
    catch (e) {
        return { _cbid, error: e.message || String(e) };
    }
}
async function dispatchAction(svc, action, p) {
    switch (action) {
        // Accounts
        case "getAccounts":
            return svc.getAccounts();
        case "getFolders":
            return svc.getFolders(p.accountId);
        // Messages
        case "getMessages":
            return svc.getMessages(p.accountId, p.folderId, p.page, p.pageSize, p.sort, p.sortDir, p.search, p.flaggedOnly);
        case "getUnifiedInbox":
            return svc.getUnifiedInbox(p.page || 1, p.pageSize || 50);
        case "getMessage":
            return svc.getMessage(p.accountId, p.uid, p.allowRemote, p.folderId);
        // Flags & actions
        case "updateFlags":
            await svc.updateFlags(p.accountId, p.uid, p.flags);
            return { ok: true };
        case "deleteMessage":
            await svc.deleteMessage(p.accountId, p.uid);
            return { ok: true };
        case "deleteMessages":
            await svc.deleteMessages(p.accountId, p.uids);
            return { ok: true, count: p.uids.length };
        case "undeleteMessage":
            await svc.undeleteMessage(p.accountId, p.uid, p.folderId);
            return { ok: true };
        case "moveMessage":
            await svc.moveMessage(p.accountId, p.uid, p.targetFolderId, p.targetAccountId);
            return { ok: true };
        case "moveMessages":
            await svc.moveMessages(p.accountId, p.uids, p.targetFolderId);
            return { ok: true, count: p.uids.length };
        case "markAsSpamMessages":
            return await svc.markAsSpamMessages(p.accountId, p.uids);
        // Folders
        case "markFolderRead":
            svc.markFolderRead(p.folderId);
            return { ok: true };
        case "createFolder":
            await svc.createFolder(p.accountId, p.parentPath, p.name);
            return { ok: true };
        case "renameFolder":
            await svc.renameFolder(p.accountId, p.folderId, p.newName);
            return { ok: true };
        case "deleteFolder":
            await svc.deleteFolder(p.accountId, p.folderId);
            return { ok: true };
        case "emptyFolder":
            await svc.emptyFolder(p.accountId, p.folderId);
            return { ok: true };
        // Compose. sendMessage validates synchronously (fast — regex check on
        // recipient strings), then writes to disk synchronously inside the
        // service. Validation errors come back immediately to the user; once
        // we've ACK'd, the message is durable on disk and the worker drains it.
        // The whole call should be sub-100ms; if it ever isn't, the [send]
        // timing log shows which step ate the budget.
        case "sendMessage":
            await svc.send(p);
            return { ok: true };
        case "saveDraft":
            return svc.saveDraft(p.accountId, p.subject, p.bodyHtml, p.bodyText, p.to, p.cc, p.previousDraftUid, p.draftId);
        case "deleteDraft":
            await svc.deleteDraft(p.accountId, p.draftUid, p.draftId);
            return { ok: true };
        // Sync
        case "syncAll":
            await svc.syncAll();
            return { ok: true };
        case "syncAccount":
            await svc.syncAccount(p.accountId);
            return { ok: true };
        case "getSyncPending":
            return svc.getSyncPending();
        case "getDiagnostics":
            return svc.getDiagnostics();
        case "getPrimaryAccount":
            return svc.getPrimaryAccount(p?.feature);
        // Calendar / Tasks: two-way cache. Reads return local immediately
        // and kick a background refresh that emits updates when done.
        case "getCalendarEvents":
            return await svc.getCalendarEvents(p.fromMs, p.toMs);
        case "createCalendarEvent":
            return { uuid: await svc.createCalendarEventLocal(p) };
        case "updateCalendarEvent":
            await svc.updateCalendarEventLocal(p.uuid, p.patch);
            return { ok: true };
        case "deleteCalendarEvent":
            await svc.deleteCalendarEventLocal(p.uuid);
            return { ok: true };
        case "getTasks":
            return await svc.getTasks(!!p.includeCompleted);
        case "createTask":
            return { uuid: await svc.createTaskLocal(p) };
        case "updateTask":
            await svc.updateTaskLocal(p.uuid, p.patch);
            return { ok: true };
        case "deleteTask":
            await svc.deleteTaskLocal(p.uuid);
            return { ok: true };
        case "drainStoreSync":
            await svc.drainStoreSync();
            return { ok: true };
        case "recordSpamReport":
            return await svc.recordSpamReport(p.accountId, p.uid, p.folderId);
        case "getOutboxStatus":
            return svc.getOutboxStatus();
        case "listQueuedOutgoing":
            return svc.listQueuedOutgoing();
        case "cancelQueuedOutgoing":
            return svc.cancelQueuedOutgoing(p.path);
        case "reauthenticate":
            return { ok: await svc.reauthenticate(p.accountId) };
        case "reauthGoogleScopes":
            return svc.reauthGoogleScopes();
        // Search & contacts
        case "searchMessages":
            return svc.search(p.query, p.page, p.pageSize, p.scope, p.accountId, p.folderId);
        case "searchContacts":
            return svc.searchContacts(p.query);
        case "hasCcHistoryTo":
            return { hasCc: svc.hasCcHistoryTo(p.email) };
        case "hasBccHistoryTo":
            return { hasBcc: svc.hasBccHistoryTo(p.email) };
        case "addContact":
            return { ok: svc.addContact(p.name, p.email) };
        case "listContacts":
            return svc.listContacts(p.query || "", p.page || 1, p.pageSize || 100);
        case "upsertContact":
            return svc.upsertContact(p.name, p.email);
        case "deleteContact":
            return svc.deleteContact(p.email);
        case "addPreferredContact":
            await svc.addPreferredContact({ name: p.name, email: p.email, source: p.source, organization: p.organization });
            return { ok: true };
        case "addToDenylist":
            await svc.addToDenylist(p.email);
            return { ok: true };
        case "loadContactsConfig":
            return { result: await svc.loadContactsConfig() };
        case "openLocalPath":
            return await svc.openLocalPath(p.which);
        case "getThreadMessages":
            return svc.getThreadMessages(p.accountId, p.threadId);
        case "readJsoncFile":
            return { content: await svc.readJsoncFile(p.name) };
        case "writeJsoncFile":
            await svc.writeJsoncFile(p.name, p.content);
            return { ok: true };
        case "formatJsonc":
            return { content: await svc.formatJsonc(p.content) };
        case "readConfigHelp":
            return { content: await svc.readConfigHelp(p.name) };
        case "unsubscribeOneClick":
            return await svc.unsubscribeOneClick(p.url);
        case "openInWord":
            return await svc.openInWord(p.editId, p.html);
        case "closeWordEdit":
            return await svc.closeWordEdit(p.editId);
        // Client-side tracing — lets webview / iframe code ship events to the
        // Node log so a "compose→send→vanished" report can be diagnosed without
        // opening devtools. Every call shows up as `[client] <tag> <data>` in
        // the main log. Keep it on the top of the switch so it's cheap + first
        // to dispatch.
        case "logClientEvent":
            console.log(`  [client] ${p.tag || "?"}${p.data ? " " + JSON.stringify(p.data).slice(0, 400) : ""}`);
            return { ok: true };
        // Settings
        case "getSettings":
            return svc.getSettings();
        case "saveSettingsData":
            svc.saveSettings(p);
            return { ok: true };
        case "allowRemoteContent":
            svc.allowRemoteContent(p.type, p.value);
            return { ok: true };
        case "flagSenderOrDomain":
            return await svc.flagSenderOrDomain(p.type, p.value);
        case "getVersion": {
            try {
                const settings = svc.getSettings();
                const storage = svc.getStorageInfo();
                return { version: rootPkg.version || "dev", theme: settings.ui?.theme || "system", storage };
            }
            catch (e) {
                console.error(`  [jsonrpc] getVersion error: ${e.message}`);
                return { version: rootPkg.version || "dev", theme: "system", storage: {} };
            }
        }
        // Autocomplete
        case "autocomplete":
            return svc.autocomplete(p);
        case "getAutocompleteSettings":
            return svc.getAutocompleteSettings();
        case "saveAutocompleteSettings":
            svc.saveAutocompleteSettings(p);
            return { ok: true };
        // AI transform (translate / proofread / summarize) — gated by per-feature
        // toggles in autocomplete settings, both default false.
        case "aiTransform":
            return svc.aiTransform(p);
        // Attachments
        case "getAttachment": {
            const att = await svc.getAttachment(p.accountId, p.uid, p.attachmentId, p.folderId);
            return { content: att.content.toString("base64"), contentType: att.contentType, filename: att.filename };
        }
        // Setup & Repair
        case "setupAccount":
            return svc.setupAccount(p.name, p.email, p.password);
        case "repairAccounts":
            return svc.repairAccounts();
        default:
            throw new Error(`Unknown action: ${action}`);
    }
}
//# sourceMappingURL=jsonrpc.js.map