/**
 * Web-compatible MailxService for Android/browser.
 * Replaces @bobfrankston/mailx-service which depends on Node.js (fs, dns, mailparser).
 *
 * Key differences from desktop:
 * - Uses WebMailxDB (wa-sqlite) instead of MailxDB (node:sqlite)
 * - Uses WebMessageStore (IndexedDB) instead of FileMessageStore (filesystem)
 * - Uses postal-mime or manual header parsing instead of mailparser's simpleParser
 * - Settings via IndexedDB + GDrive API instead of filesystem
 * - No dns.resolveMx — provider detection is static (Gmail/Outlook/Yahoo/iCloud)
 */
import type { WebMailxDB } from "./db.js";
import type { WebMessageStore } from "./web-message-store.js";
import type { Folder, AutocompleteSettings, MailxApi } from "@bobfrankston/mailx-types";
import { type ReminderState } from "@bobfrankston/mailx-types";
export interface WebSyncManager {
    syncAll(): Promise<void>;
    syncFolders(accountId: string): Promise<Folder[]>;
    syncFolder(accountId: string, folderId: number): Promise<void>;
    fetchMessageBody(accountId: string, folderId: number, uid: number): Promise<Uint8Array | null>;
    updateFlagsLocal(accountId: string, uid: number, folderId: number, flags: string[]): Promise<void>;
    trashMessage(accountId: string, folderId: number, uid: number): Promise<void>;
    trashMessages(accountId: string, messages: {
        uid: number;
        folderId: number;
    }[]): Promise<void>;
    moveMessage(accountId: string, uid: number, folderId: number, targetFolderId: number): Promise<void>;
    moveMessages(accountId: string, messages: {
        uid: number;
        folderId: number;
    }[], targetFolderId: number): Promise<void>;
    moveMessageCrossAccount(accountId: string, uid: number, folderId: number, targetAccountId: string, targetFolderId: number): Promise<void>;
    undeleteMessage(accountId: string, uid: number, folderId: number): Promise<void>;
    queueOutgoingLocal(accountId: string, rawMessage: string): void | Promise<void>;
    saveDraft(accountId: string, raw: string, previousDraftUid?: number, draftId?: string): Promise<number | null>;
    deleteDraft(accountId: string, draftUid: number): Promise<void>;
    reauthenticate(accountId: string): Promise<boolean>;
    searchOnServer(accountId: string, folderPath: string, criteria: any): Promise<number[]>;
    syncAllContacts(): Promise<void>;
    addAccount(account: any): Promise<void>;
    on(event: string, handler: (...args: any[]) => void): void;
    emit(event: string, ...args: any[]): void;
}
export declare class WebMailxService implements MailxApi {
    private db;
    private bodyStore;
    private syncManager;
    constructor(db: WebMailxDB, bodyStore: WebMessageStore, syncManager: WebSyncManager);
    getAccounts(): Promise<any[]>;
    getFolders(accountId: string): Folder[];
    getUnifiedInbox(page?: number, pageSize?: number): any;
    getMessages(accountId: string, folderId: number, page?: number, pageSize?: number, sort?: string, sortDir?: string, search?: string): any;
    getMessage(accountId: string, uid: number, allowRemote?: boolean, folderId?: number): Promise<any>;
    /** Flag (or unflag) a sender / domain. Mirrors the desktop service so
     *  the viewer's right-click "Flag sender" / "Flag domain" buttons work
     *  on phone — was a no-op on Android before. Toggles membership in
     *  flaggedSenders / flaggedDomains in allowlist.jsonc, which syncs
     *  back to the cloud copy. */
    flagSenderOrDomain(type: "sender" | "domain", value: string): Promise<{
        flagged: boolean;
    }>;
    updateFlags(accountId: string, uid: number, flags: string[]): Promise<void>;
    allowRemoteContent(type: "sender" | "domain" | "recipient", value: string): Promise<void>;
    search(q: string, page?: number, pageSize?: number, scope?: string, accountId?: string, folderId?: number): Promise<any>;
    getSyncPending(): {
        pending: number;
    };
    syncAll(): Promise<void>;
    syncAccount(accountId: string): Promise<void>;
    reauthenticate(accountId: string): Promise<boolean>;
    send(msg: any): Promise<void>;
    deleteMessage(accountId: string, uid: number): Promise<void>;
    deleteMessages(accountId: string, uids: number[]): Promise<void>;
    moveMessage(accountId: string, uid: number, targetFolderId: number, targetAccountId?: string): Promise<void>;
    moveMessages(accountId: string, uids: number[], targetFolderId: number): Promise<void>;
    undeleteMessage(accountId: string, uid: number, folderId: number): Promise<void>;
    saveDraft(accountId: string, subject: string, bodyHtml: string, bodyText: string, to?: string, cc?: string, previousDraftUid?: number, draftId?: string, bcc?: string, from?: string): Promise<{
        draftUid: number | null;
        draftId: string;
    }>;
    deleteDraft(accountId: string, draftUid: number): Promise<void>;
    searchContacts(query: string): any[];
    /** Re-pull contacts.jsonc only when the Drive copy actually changed.
     *  One metadata request (cloudStat) throttled to a few minutes; the
     *  full download + reload runs only on a new modifiedTime. Kicked from
     *  autocomplete, the periodic sync tick, and app-resume. */
    private _contactsStatAt;
    private _contactsModifiedTime;
    private static readonly CONTACTS_STAT_MS;
    maybeRefreshContactsConfig(): Promise<void>;
    /** Address-book listing — paginated, filterable. Mirrors mailx-service's
     *  signature so the same client-side address-book modal works on Android
     *  without an "ipc(...).listContacts is not a function" crash. */
    listContacts(query: string, page?: number, pageSize?: number): {
        items: any[];
        total: number;
        page: number;
        pageSize: number;
    };
    /** Manual upsert from the address-book UI. The desktop path queues a
     *  Google People sync; Android relies on the desktop pushing changes
     *  back, so this is local-only for now. */
    upsertContact(name: string, email: string): {
        ok: true;
    };
    deleteContact(email: string): {
        ok: true;
    };
    addContact(name: string, email: string): boolean;
    /** Q49 heuristic mirror: true if the user has ever sent a message to
     *  `recipientEmail` that had a non-empty Cc field. Compose uses this to
     *  decide whether to auto-expand the Cc row on reply. */
    hasCcHistoryTo(recipientEmail: string): boolean;
    getSettings(): Promise<any>;
    saveSettingsData(settings: any): Promise<void>;
    getStorageInfo(): {
        provider: string;
        mode: string;
        folderId?: string;
        folderName?: string;
        folderPath?: string;
        folderOwner?: string;
    };
    markFolderRead(folderId: number): void;
    getAutocompleteSettings(): Promise<AutocompleteSettings>;
    saveAutocompleteSettings(settings: AutocompleteSettings): Promise<void>;
    autocomplete(_req: any): Promise<{
        suggestion: string;
    }>;
    resetStore(): Promise<void>;
    readJsoncFile(name: string): Promise<string | null>;
    writeJsoncFile(name: string, content: string): Promise<void>;
    formatJsonc(content: string): Promise<string>;
    readConfigHelp(_name: string): Promise<string>;
    /** Compute and return the priority sender / domain index from the
     *  current contacts.jsonc. Reads from cloud (or local cache) every
     *  call — small file, simpler than maintaining a long-lived cache. */
    getPriorityLists(): Promise<{
        senders: string[];
        domains: string[];
    }>;
    setPrioritySender(email: string, value: boolean, name?: string): Promise<void>;
    setPriorityDomain(domain: string, value: boolean): Promise<void>;
    sendMessage(msg: any): Promise<void>;
    searchMessages(query: string, page?: number, pageSize?: number, scope?: string, accountId?: string, folderId?: number, _includeTrashSpam?: boolean): Promise<any>;
    private notImpl;
    getThreadMessages(_accountId: string, _threadId: string): any;
    getMessageSource(_accountId: string, _uid: number, _folderId?: number): Promise<{
        dataBase64: string;
        filename: string;
    }>;
    getAttachment(_accountId: string, _uid: number, _attachmentId: number, _folderId?: number): Promise<{
        content: any;
        contentType: string;
        filename: string;
    }>;
    openAttachment(_accountId: string, _uid: number, _attachmentId: number, _folderId?: number): Promise<{
        ok: boolean;
        path: string;
    }>;
    /** Mark as spam = move to the account's \Junk folder, exactly as desktop's
     *  MailxService.markAsSpamMessages does. This was a notImpl() stub, which
     *  is worse than it sounds: the client optimistically removes the rows
     *  from the list BEFORE calling this, then only writes the rejection to
     *  the status bar. So on Android the spam button looked like it worked,
     *  nothing moved on the server, and the next sync brought every message
     *  straight back (Bob 2026-08-07: "attempts to delete spam but they keep
     *  coming back"). moveMessages was implemented all along — spam just never
     *  got wired to it. */
    markAsSpamMessages(accountId: string, uids: number[]): Promise<{
        targetFolderId: number;
        moved: number;
    }>;
    recordSpamReport(_accountId: string, _uid: number, _folderId: number): Promise<any>;
    createFolder(_accountId: string, _parentPath: string, _name: string): Promise<void>;
    renameFolder(_accountId: string, _folderId: number, _newName: string): Promise<void>;
    deleteFolder(_accountId: string, _folderId: number): Promise<void>;
    moveFolderToTrash(_accountId: string, _folderId: number): Promise<void>;
    emptyFolder(_accountId: string, _folderId: number): Promise<void>;
    getOutboxStatus(): any;
    listQueuedOutgoing(): any[];
    cancelQueuedOutgoing(_filePath: string): {
        ok: true;
    };
    drainStoreSync(): Promise<void>;
    reauthGoogleScopes(): {
        cleared: number;
    };
    /** No per-folder sync lane on Android — a folder "sync now" refreshes the
     *  whole account (cheap: Gmail incremental sync / one IMAP pass). */
    syncFolderNow(accountId: string, _folderId: number): Promise<void>;
    cancelServerSearch(): void;
    copyMessages(_accountId: string, _uids: number[], _folderIds: number[] | undefined, _targetFolderId: number): Promise<void>;
    /** `{}` = play the built-in chime — no custom sound files on Android. */
    getReminderSound(): Promise<{
        mute?: boolean;
        dataBase64?: string;
        mime?: string;
    }>;
    addPreferredContact(entry: {
        name: string;
        email: string;
        source?: string;
        organization?: string;
    }): Promise<void>;
    addToDenylist(email: string): Promise<void>;
    hasBccHistoryTo(_email: string): boolean;
    /** Pull the shared GDrive `contacts.jsonc` and merge its entries into the
     *  local contacts table. Desktop flushes the full union there (everything
     *  it discovered from its mailbox corpus + Google contacts + preferred);
     *  this is how an Android device gets contacts it never saw in its own
     *  (partial) on-device corpus. Called at startup AND on a periodic tick /
     *  app-resume / after a ⊘ so a denylist edit made on another device
     *  reaches a running phone (Bob 2026-07-07: GDrive edit was still being
     *  offered). The denylist refresh runs every call; the contact IMPORT
     *  runs once per session — recordSentAddress bumps `use_count`, so
     *  re-importing on every reload would inflate autocomplete rank. */
    private _contactsImported;
    loadContactsConfig(): Promise<any>;
    getCalendarEvents(_fromMs: number, _toMs: number): Promise<any[]>;
    getCalendars(): Promise<Array<{
        id: string;
        name: string;
        color: string;
        primary: boolean;
    }>>;
    createCalendarEvent(_ev: any): Promise<{
        uuid: string;
    }>;
    updateCalendarEvent(_uuid: string, _patch: any): Promise<{
        ok: true;
    }>;
    deleteCalendarEvent(_uuid: string): Promise<{
        ok: true;
    }>;
    getTasks(_includeCompleted?: boolean): Promise<any[]>;
    createTask(_t: {
        title: string;
        notes?: string;
        dueMs?: number;
    }): Promise<{
        uuid: string;
    }>;
    updateTask(_uuid: string, _patch: any): Promise<{
        ok: true;
    }>;
    deleteTask(_uuid: string): Promise<{
        ok: true;
    }>;
    private reminderStateCache;
    getReminderState(): Promise<ReminderState>;
    mergeReminderState(patch: any): Promise<ReminderState>;
    getUserDict(): Promise<string[]>;
    addUserDictWord(_word: string): Promise<string[]>;
    addUserDictWords(_words: string[]): Promise<string[]>;
    removeUserDictWord(_word: string): Promise<string[]>;
    getDiagnostics(): any;
    getPrimaryAccount(_feature?: string): any;
    getVersion(): any;
    consumePendingMailto(): any;
    logClientEvent(..._args: any[]): void;
    setupAccount(_name: string, _email: string, _password?: string): Promise<{
        ok: boolean;
        error?: string;
        message?: string;
    }>;
    repairAccounts(): Promise<{
        ok: boolean;
        error?: string;
        message?: string;
    }>;
    unsubscribeOneClick(_url: string): Promise<{
        ok: boolean;
        status: number;
        statusText: string;
    }>;
    aiTransform(_req: any): Promise<any>;
}
//# sourceMappingURL=web-service.d.ts.map