import { ImapFlow } from "imapflow";
import type { EmailConfig } from "./credentials.js";
export interface EmailMessage {
    uid: number;
    messageId: string | null;
    inReplyTo: string | null;
    from: string;
    subject: string;
    date: string;
    bodyPreview: string;
    attachments: AttachmentMeta[];
}
export interface PaginatedMessages {
    messages: EmailMessage[];
    /** Pass as before_uid to get the next page of older messages. Omitted when results are exhausted. */
    nextBeforeUid?: number;
}
export declare const MAX_LIMIT = 50;
/**
 * Resolve an IMAP folder name from a logical folder key.
 * - "inbox" → "INBOX"
 * - "sent" → discovered via \Sent special-use flag (RFC 6154)
 *
 * Throws if the requested folder cannot be found on this server.
 */
export declare function resolveFolderName(client: ImapFlow, folder: "inbox" | "sent"): Promise<string>;
/**
 * Strip HTML tags and decode common entities.
 * Used for extracting readable text from HTML-only email bodies.
 */
export declare function stripHtml(html: string): string;
/** Hard cap on a single attachment's bytes — over this size, metadata is surfaced
 *  but bytes are not downloaded. Matches typical provider send limits. */
export declare const MAX_ATTACHMENT_BYTES: number;
/** Attachment metadata as derived from IMAP bodyStructure — no bytes. */
export interface AttachmentMeta {
    /** IMAP body part key, e.g. "2" or "1.3". Used to fetch bytes later. */
    partKey: string;
    filename: string;
    mimeType: string;
    sizeBytes: number;
    /** RFC 2045 transfer encoding — needed to decode bytes at fetch time. */
    encoding: string | null;
}
/**
 * Body-structure node shape (subset of ImapFlow's BodyStructure).
 * Defined locally because ImapFlow does not export a public type for this.
 */
interface BodyStructureNode {
    part?: string;
    type?: string;
    encoding?: string;
    size?: number;
    disposition?: string;
    dispositionParameters?: {
        filename?: string;
    };
    parameters?: {
        name?: string;
    };
    childNodes?: BodyStructureNode[];
}
/**
 * Walk an IMAP bodyStructure and return metadata for every attachment-shaped
 * part. No bytes are downloaded — cheap, runs at preview time.
 *
 * An attachment-shaped part is one of:
 *  - disposition === "attachment" (RFC 2183), OR
 *  - has a filename in parameters.name or dispositionParameters.filename AND
 *    is not a multipart container.
 *
 * Inline parts without a filename (e.g. the message body) are excluded.
 */
export declare function walkAttachmentMetadata(structure: BodyStructureNode | undefined): AttachmentMeta[];
/**
 * Format an AttachmentMeta[] as a single-line operator-readable footer.
 * Returns empty string when the array is empty so callers can skip the
 * line entirely.
 */
export declare function formatAttachmentsFooter(attachments: AttachmentMeta[]): string;
/**
 * Result of attempting to fetch one attachment's bytes from IMAP.
 * `bytes === null` indicates a non-fatal failure (oversize, short buffer,
 * fetch error) — the caller surfaces metadata-only graph attach instead.
 */
export interface AttachmentBytesResult {
    uid: number;
    partKey: string;
    bytes: Buffer | null;
    failureReason: "oversize" | "short-buffer" | "fetch-error" | null;
}
/**
 * Download decoded bytes for a list of (uid, partKey) attachments from IMAP.
 * Opens one connection, reuses it across all requests. Per-attachment
 * failures are isolated — one bad part does not abort the batch.
 */
export declare function fetchAttachmentBytesForMessages(config: EmailConfig, password: string, requests: Array<{
    uid: number;
    partKey: string;
    expectedSize: number;
    encoding: string | null;
}>): Promise<AttachmentBytesResult[]>;
/**
 * Decode a raw IMAP body part buffer according to its transfer encoding.
 * Returns a UTF-8 string. Falls back to raw UTF-8 for unknown encodings.
 */
export declare function decodeBodyPart(buf: Buffer, encoding?: string): string;
/**
 * Extract a text body preview from a fetched message's inline bodyParts + bodyStructure.
 *
 * Determines the content type and transfer encoding of part "1" from
 * bodyStructure (single-part: structure itself, multipart: first childNode).
 * Skips non-text parts and multipart containers. Strips HTML. Truncates
 * to BODY_PREVIEW_LENGTH characters.
 */
export declare function extractBodyFromFetch(msg: {
    bodyParts?: Map<string, Buffer>;
    bodyStructure?: {
        type?: string;
        encoding?: string;
        childNodes?: Array<{
            type?: string;
            encoding?: string;
        }>;
    };
}): string;
/**
 * Test IMAP connectivity and authentication.
 * Returns null on success, error message on failure.
 */
export declare function testConnection(config: EmailConfig, password: string): Promise<string | null>;
/**
 * Check whether an IMAP envelope's TO field contains the target address.
 * Case-insensitive comparison. Strict: if the server didn't return TO
 * addresses, the message is excluded — we cannot confirm it was addressed
 * to the target.
 */
export declare function matchesRecipient(envelope: {
    to?: Array<{
        name?: string;
        address?: string;
    }>;
}, targetAddress: string): boolean;
/**
 * Build IMAP SEARCH criteria for fetchRecent.
 * Never includes TO — that filter is applied client-side to avoid
 * full-mailbox header scans that timeout on large mailboxes.
 */
export declare function buildFetchRecentCriteria(options: {
    sender?: string;
    since?: Date;
    before?: Date;
    to?: string;
    limit?: number;
}): {
    criteria: Record<string, unknown>;
    clientSideTo: string | undefined;
    fetchLimit: number;
};
/**
 * Build IMAP SEARCH criteria for searchMessages.
 * Never includes TO — that filter is applied client-side.
 * When TO was the only filter (no other criteria provide bounding),
 * injects a since floor to prevent unbounded full-mailbox scans.
 */
export declare function buildSearchCriteria(options: {
    sender?: string;
    subject?: string;
    body?: string;
    since?: Date;
    before?: Date;
    to?: string;
}): {
    criteria: Record<string, unknown>;
    clientSideTo: string | undefined;
};
/**
 * Fetch recent messages from a mailbox folder.
 * Returns the most recent N messages with cursor-based pagination.
 *
 * TO filtering is applied client-side (not via IMAP SEARCH) to avoid
 * full-mailbox header scans that exceed socketTimeout on large mailboxes.
 */
export declare function fetchRecent(config: EmailConfig, password: string, options?: {
    limit?: number;
    sender?: string;
    subjectPattern?: string;
    since?: Date;
    before?: Date;
    to?: string;
    folder?: "inbox" | "sent";
    beforeUid?: number;
}): Promise<PaginatedMessages>;
/**
 * Search a mailbox folder by query criteria with cursor-based pagination.
 */
export declare function searchMessages(config: EmailConfig, password: string, query: {
    sender?: string;
    subject?: string;
    body?: string;
    since?: Date;
    before?: Date;
    limit?: number;
    to?: string;
    folder?: "inbox" | "sent";
    beforeUid?: number;
}): Promise<PaginatedMessages>;
/**
 * Result from an incremental email fetch performed by the email-fetch tool.
 * Includes the raw envelope data needed for graph storage (not just display).
 */
export interface FetchedEmail {
    uid: number;
    messageId: string | null;
    inReplyTo: string | null;
    toAddresses: string[];
    ccAddresses: string[];
    fromAddress: string;
    fromName: string | null;
    subject: string;
    date: string;
    bodyPreview: string;
    /** Attachment metadata derived from bodyStructure; bytes downloaded later. */
    attachments: AttachmentMeta[];
}
/**
 * Fetch emails from INBOX since a given UID (exclusive) for incremental polling.
 * Returns the UIDVALIDITY and all matching messages with UID > sinceUid.
 *
 * When sinceUid is 0 (first poll), fetches emails from the last 7 days
 * to avoid pulling the entire mailbox on large accounts.
 *
 * Client-side TO filtering is applied when recipientAddress differs
 * from the auth email (alias/catchall scenarios).
 */
export declare function fetchSinceUid(config: EmailConfig, password: string, sinceUid: number, recipientAddress: string): Promise<{
    uidValidity: number;
    emails: FetchedEmail[];
    maxUid: number;
}>;
/**
 * Resolve an envelope by Message-ID via IMAP. Searches INBOX first, then
 * the \Sent special-use folder. Returns null when no folder yields a hit.
 *
 * Uses `header: { "message-id": ... }` IMAP SEARCH — sufficient on every
 * server that honours RFC 3501 header search. The Message-ID is sent with
 * angle brackets restored because some servers (notably Gmail) only match
 * the raw header value, not the bare identifier.
 */
export declare function fetchEnvelopeByMessageId(config: EmailConfig, password: string, messageId: string): Promise<{
    uid: number;
    mailbox: string;
    messageId: string;
    fromAddress: string;
    fromName: string | null;
    toAddresses: string[];
    ccAddresses: string[];
    subject: string;
    date: string;
} | null>;
/**
 * Get the inbox message count.
 */
export declare function getInboxCount(config: EmailConfig, password: string): Promise<number>;
export {};
//# sourceMappingURL=imap.d.ts.map