export const MESSAGE_PROVIDERS = ['imessage', 'icloud'] as const;
export type MessageProvider = (typeof MESSAGE_PROVIDERS)[number];

export interface Message {
  readonly id: string;
  readonly deviceId: string;
  readonly conversationId: string;
  readonly externalId: string;
  readonly provider: MessageProvider;
  readonly fromHandle: string;
  readonly body: string;
  readonly isFromMe: boolean;
  readonly hasAttachments: boolean;
  readonly attachmentCount: number;
  readonly attachmentMimeTypes: readonly string[];
  readonly sentAt: string;
  readonly deliveredAt: string | null;
  readonly readAt: string | null;
  readonly syncedAt: string;
  // Rich-message metadata
  readonly attributedBody: string | null;
  /** Server-side decoded plain text from the attributedBody typedstream blob. */
  readonly bodyDecoded: string | null;
  readonly associatedMessageType: number | null;
  readonly associatedMessageGuid: string | null;
  readonly expressiveSendStyleId: string | null;
  readonly balloonBundleId: string | null;
  readonly isAudioMessage: boolean;
  readonly replyToGuid: string | null;
  readonly threadOriginatorGuid: string | null;
  readonly groupTitle: string | null;
  readonly service: string | null;
  readonly senderIdentifier: string | null;
  readonly senderDisplayName: string | null;
  readonly senderPhoneNumber: string | null;
  readonly senderEmail: string | null;
}

export interface MessageDraft {
  readonly id: string;
  readonly deviceId: string;
  readonly conversationId: string;
  readonly externalId: string;
  readonly provider: MessageProvider;
  readonly fromHandle: string;
  readonly body: string;
  readonly isFromMe: boolean;
  readonly hasAttachments?: boolean;
  readonly attachmentCount?: number;
  readonly sentAt: string;
  readonly deliveredAt?: string | null;
  readonly readAt?: string | null;
  // Rich-message metadata (all optional — not every message has them)
  readonly attributedBody?: string | null;      // base64 blob from Swift; stored as BYTEA
  /** Server-side decoded plain text — usually omitted by the client and computed lazily. */
  readonly bodyDecoded?: string | null;
  readonly associatedMessageType?: number | null;
  readonly associatedMessageGuid?: string | null;
  readonly expressiveSendStyleId?: string | null;
  readonly balloonBundleId?: string | null;
  readonly isAudioMessage?: boolean | null;
  readonly replyToGuid?: string | null;
  readonly threadOriginatorGuid?: string | null;
  readonly groupTitle?: string | null;
  readonly service?: string | null;
  readonly senderIdentifier?: string | null;
  readonly senderDisplayName?: string | null;
  readonly senderPhoneNumber?: string | null;
  readonly senderEmail?: string | null;
}

export interface MessageFilter {
  readonly conversationId?: string;
  readonly deviceId?: string;
  readonly provider?: MessageProvider;
  readonly since?: string;
  readonly limit?: number;
}

export type SearchMode = 'lexical' | 'semantic' | 'hybrid';

export interface MessageSearchFilter {
  readonly query: string;
  readonly mode?: SearchMode;
  readonly conversationId?: string;
  readonly deviceId?: string;
  readonly provider?: MessageProvider;
  readonly limit?: number;
  readonly offset?: number;
  /**
   * ISO timestamp — results query filters to `synced_at > since`.
   * Does NOT affect the `total` count (which always reflects all matches).
   * Lexical and semantic only; hybrid ignores this and always returns full ranked results.
   */
  readonly since?: string;
  /** Pre-computed query embedding — used for semantic/hybrid modes. */
  readonly queryEmbedding?: number[];
}

export interface MessageSearchHit {
  readonly message: Message;
  readonly rank: number;
  readonly snippet: string;
  /** Which mode produced this hit */
  readonly mode: SearchMode;
}

export interface SearchResult {
  readonly hits: readonly MessageSearchHit[];
  /** True total match count — unaffected by limit/offset/since. */
  readonly total: number;
}
