import { ConversationsRemoteConfig } from "@posthog/browser-common";
import { PostHog } from './module';
//#region lib/src/posthog-conversations-types.d.ts
/**
 * Author types for messages in a conversation
 */
type MessageAuthorType = 'customer' | 'AI' | 'human';
/**
 * TipTap mark types for inline formatting
 */
interface TipTapMark {
  type: 'bold' | 'italic' | 'underline' | 'strike' | 'code' | 'link';
  attrs?: {
    href?: string;
    target?: string;
    [key: string]: unknown;
  };
}
/**
 * TipTap node representing content in the document tree
 */
interface TipTapNode {
  type: string;
  attrs?: Record<string, unknown>;
  content?: TipTapNode[];
  marks?: TipTapMark[];
  text?: string;
}
/**
 * TipTap document - the root node of rich content
 */
interface TipTapDoc {
  type: 'doc';
  content?: TipTapNode[];
}
/**
 * A message in a conversation
 */
interface Message {
  /**
   * Unique identifier for the message
   */
  id: string;
  /**
   * The message content as plain text (fallback)
   */
  content: string;
  /**
   * Rich content in TipTap JSON format (preferred for rendering)
   * Falls back to `content` if missing or invalid
   */
  rich_content?: TipTapDoc;
  /**
   * Type of the message author
   */
  author_type: MessageAuthorType;
  /**
   * Display name of the message author
   */
  author_name?: string;
  /**
   * ISO timestamp when the message was created
   */
  created_at: string;
  /**
   * Whether this is an internal note (not shown to customer)
   */
  is_private: boolean;
}
/**
 * Status of a support ticket
 */
type TicketStatus = 'new' | 'open' | 'pending' | 'on_hold' | 'resolved';
/**
 * A support ticket in the conversations system
 */
interface Ticket {
  /**
   * Unique identifier for the ticket
   */
  id: string;
  /**
   * Current status of the ticket
   */
  status: TicketStatus;
  /**
   * Preview of the last message
   */
  last_message?: string;
  /**
   * ISO timestamp of the last message
   */
  last_message_at?: string;
  /**
   * Total number of messages in this ticket
   */
  message_count: number;
  /**
   * ISO timestamp when the ticket was created
   */
  created_at: string;
  /**
   * Array of messages (only present in detailed ticket view)
   */
  messages?: Message[];
  /**
   * Number of unread messages from the team
   */
  unread_count?: number;
}
/**
 * Response from sending a message
 */
interface SendMessageResponse {
  /**
   * ID of the ticket this message belongs to
   */
  ticket_id: string;
  /**
   * ID of the newly created message
   */
  message_id: string;
  /**
   * Current status of the ticket
   */
  ticket_status: TicketStatus;
  /**
   * ISO timestamp when the message was created
   */
  created_at: string;
  /**
   * Number of unread messages from the team
   * After customer sends a message, this is always 0
   */
  unread_count: number;
}
/**
 * Response from fetching messages
 */
interface GetMessagesResponse {
  /**
   * ID of the ticket
   */
  ticket_id: string;
  /**
   * Current status of the ticket
   */
  ticket_status: TicketStatus;
  /**
   * Array of messages
   */
  messages: Message[];
  /**
   * Whether there are more messages to fetch
   */
  has_more: boolean;
  /**
   * Number of unread messages from the team
   */
  unread_count: number;
}
/**
 * Response from marking messages as read
 */
interface MarkAsReadResponse {
  /**
   * Whether the operation was successful
   */
  success: boolean;
  /**
   * Number of unread messages (should be 0 after marking as read)
   */
  unread_count: number;
}
/**
 * Options for fetching tickets list
 */
interface GetTicketsOptions {
  /**
   * Filter by ticket status (e.g., 'open', 'closed')
   */
  status?: string;
  /**
   * Number of tickets to return (default: 20)
   */
  limit?: number;
  /**
   * Pagination offset (default: 0)
   */
  offset?: number;
}
/**
 * Response from fetching tickets list
 */
interface GetTicketsResponse {
  /**
   * Total count of tickets
   */
  count: number;
  /**
   * Array of tickets
   */
  results: Ticket[];
}
type RestoreFromTokenStatus = 'success' | 'expired' | 'invalid' | 'used';
/**
 * Response from restore token exchange endpoint
 */
interface RestoreFromTokenResponse {
  /**
   * Restore result
   */
  status: RestoreFromTokenStatus;
  /**
   * Canonical widget session ID to use after restore
   */
  widget_session_id?: string;
  /**
   * Migrated ticket IDs, if any
   */
  migrated_ticket_ids?: string[];
  /**
   * Optional machine-readable backend code
   */
  code?: string;
}
/**
 * Response from self-service restore link request
 */
interface RequestRestoreLinkResponse {
  ok: true;
}
/**
 * User-provided identification data (collected via the widget form)
 */
interface UserProvidedTraits {
  name?: string;
  email?: string;
}
//#endregion
//#region lib/src/utils/globals.d.ts
interface LazyLoadedConversationsInterface {
  show: () => void;
  hide: () => void;
  isVisible: () => boolean;
  reset: () => void;
  setIdentity: () => void;
  clearIdentity: () => void;
  sendMessage: (message: string, userTraits?: UserProvidedTraits, newTicket?: boolean) => Promise<SendMessageResponse>;
  getMessages: (ticketId?: string, after?: string) => Promise<GetMessagesResponse>;
  markAsRead: (ticketId?: string) => Promise<MarkAsReadResponse>;
  getTickets: (options?: GetTicketsOptions) => Promise<GetTicketsResponse>;
  requestRestoreLink: (email: string) => Promise<RequestRestoreLinkResponse>;
  restoreFromToken: (restoreToken: string) => Promise<RestoreFromTokenResponse>;
  restoreFromUrlToken: () => Promise<RestoreFromTokenResponse | null>;
  getCurrentTicketId: () => string | null;
  getWidgetSessionId: () => string;
}
//#endregion
//#region lib/src/extensions/conversations/posthog-conversations.d.ts
type ConversationsManager$1 = LazyLoadedConversationsInterface;
//#endregion
//#region lib/src/extensions/conversations/external/index.d.ts
declare class ConversationsManager implements ConversationsManager$1 {
  private readonly _posthog;
  private _config;
  private _persistence;
  private _widgetRef;
  private _containerElement;
  private _currentTicketId;
  private _pollTimeoutId;
  private _pollLoopRunning;
  private _pollGeneration;
  private _consecutivePollingRateLimitFailures;
  private _reattachIntervalId;
  private _lastMessageTimestamp;
  private _isPollingMessages;
  private _isPollingTickets;
  private _unsubscribeIdentifyListener;
  private _unreadCount;
  private _widgetSessionId;
  private _isWidgetEnabled;
  private _isDomainAllowed;
  private _widgetState;
  private _isWidgetRendered;
  private _hasProcessedRestoreToken;
  private _initializeWidgetPromise;
  private _lifecycleGeneration;
  private _currentView;
  private _tickets;
  private _showTicketList;
  private _consecutivePollingStatusZeroFailures;
  constructor(config: ConversationsRemoteConfig, _posthog: PostHog);
  private _onOnline;
  private _currentUrl;
  /**
   * Send a message programmatically via the API
   * Creates a new ticket if none exists or if newTicket is true
   *
   * @param message - The message text to send
   * @param userTraits - Optional user identification data (name, email)
   * @param newTicket - If true, forces creation of a new ticket (ignores current ticket)
   * @returns Promise with the response including ticket_id and message_id
   */
  sendMessage(message: string, userTraits?: UserProvidedTraits, newTicket?: boolean): Promise<SendMessageResponse>;
  /**
   * Switch to a different ticket if an explicit ticketId is provided
   * This ensures subsequent operations (sendMessage, etc.) use the correct ticket
   */
  private _switchToTicketIfNeeded;
  /** Fetch messages via the API */
  getMessages(ticketId?: string, after?: string): Promise<GetMessagesResponse>;
  /** Mark messages as read via the API */
  markAsRead(ticketId?: string): Promise<MarkAsReadResponse>;
  /**
   * Initialize the conversations manager.
   * Always initializes persistence and event listeners for API usage.
   * Only renders the widget if widgetEnabled is true AND domain is allowed.
   */
  private _initialize;
  private _completeInitialization;
  private _restoreFromTokenWithRetry;
  private _restoreFromToken;
  /**
   * Initialize and render the widget UI
   * Uses a promise guard to prevent race conditions from concurrent calls
   */
  private _initializeWidget;
  private _doInitializeWidget;
  /**
   * Extract name and email from PostHog's stored person properties.
   *
   * Person properties set via posthog.identify() are stored under the
   * $stored_person_properties persistence key, not as top-level props.
   * We check both locations plus the super-properties for completeness.
   */
  private _getPersonTraits;
  /**
   * Get initial user traits from PostHog or localStorage
   */
  private _getInitialUserTraits;
  /**
   * Handle user identification from the widget form
   */
  private _handleIdentify;
  private _handleRequestRestoreLink;
  /**
   * Handle sending a message from the widget
   */
  private _handleSendMessage;
  /**
   * Handle widget state changes
   */
  private _handleStateChange;
  /**
   * Mark messages as read
   */
  private _markMessagesAsRead;
  /**
   * Load messages for the current ticket
   */
  private _loadMessages;
  private _isWidgetOpen;
  /**
   * Poll for new messages
   */
  private _pollMessages;
  /**
   * Poll for tickets list
   */
  private _pollTickets;
  /**
   * Load tickets list from API
   */
  private _loadTickets;
  private _computeShowTicketList;
  private _isCurrentTicketResolved;
  /**
   * Patch the local _tickets cache with a new status for a given ticket and push
   * any UI-relevant changes (resolved lock + list visibility) to the widget.
   */
  private _applyTicketStatusUpdate;
  /**
   * Main poll function that polls based on current view
   */
  private _poll;
  private _trackPollingEndpointReachability;
  /**
   * Track HTTP 429s on polling requests so the loop can back off. Any 2xx
   * clears the streak; a 429 lengthens the next poll delay exponentially.
   */
  private _trackPollingRateLimit;
  /**
   * Handle view changes from the widget
   */
  private _handleViewChange;
  /**
   * Handle ticket selection from the list
   */
  private _handleSelectTicket;
  /**
   * Handle new conversation request
   */
  private _handleNewConversation;
  /**
   * Handle back to tickets request
   */
  private _handleBackToTickets;
  /**
   * Determine initial view based on ticket count
   */
  private _determineInitialView;
  /**
   * Apply a fetched ticket list to internal state and return the appropriate view.
   * Shared by _determineInitialView (widget boot) and _loadTicketsAndReconcileView
   * (identity change at runtime).
   */
  private _applyTicketsToState;
  /**
   * Start the self-scheduling poll loop.
   *
   * Idempotent: safe to call from any state-changing handler (send, restore,
   * identity change, ticket selection). The loop polls immediately, then
   * reschedules itself with a delay derived from widget state and rate-limit
   * backoff (see _nextPollDelayMs), and stops itself when there is nothing to
   * poll (see _hasSomethingToPoll).
   */
  private _startPolling;
  private _pollThenSchedule;
  /**
   * Schedule the next poll, or stop the loop when there is nothing to poll.
   * An idle widget with no conversation generates zero polling traffic.
   */
  private _scheduleNextPoll;
  /**
   * Delay before the next poll: exponential backoff while rate limited,
   * otherwise the open/closed cadence.
   */
  private _nextPollDelayMs;
  /**
   * Whether the current view has anything worth polling for. Messages view
   * needs an active ticket; tickets view needs at least one ticket. The
   * restore-request view never polls.
   */
  private _hasSomethingToPoll;
  /**
   * Stop the poll loop.
   */
  private _stopPolling;
  /**
   * Re-attach the widget container if it has been detached from the DOM.
   *
   * SPA frameworks such as Turbo Drive (Hotwire) and Rails Turbo replace the
   * entire document.body on navigation. That removes our container — which was
   * appended to body in _renderWidget — without any teardown call, so the
   * widget silently disappears until a full page reload. Re-attaching the same
   * element (rather than re-rendering) preserves widget state and avoids
   * refetching messages.
   */
  private _reattachWidgetIfDetached;
  /**
   * Start watching for the widget being detached from the DOM (e.g. by an SPA
   * navigation that replaces document.body) and re-attach it when it happens.
   */
  private _startReattachWatcher;
  /**
   * Stop the DOM re-attach watcher.
   */
  private _stopReattachWatcher;
  /**
   * Setup listener for identify events.
   * When user calls posthog.identify(), hide the identification form
   * since we now know who they are.
   */
  private _setupIdentifyListener;
  /**
   * Show the widget (render it to DOM).
   * The widget respects its saved state (open/closed).
   * Note: Domain restrictions still apply - widget won't render on disallowed domains.
   */
  show(): void;
  /**
   * Hide and remove the widget from the DOM.
   * Conversation data is preserved - call show() to re-render.
   */
  hide(): void;
  /**
   * Check if the widget is currently visible (rendered in DOM)
   */
  isVisible(): boolean;
  /** Get tickets list for the current widget session or verified identity */
  getTickets(options?: GetTicketsOptions): Promise<GetTicketsResponse>;
  requestRestoreLink(email: string): Promise<RequestRestoreLinkResponse>;
  restoreFromToken(restoreToken: string): Promise<RestoreFromTokenResponse>;
  restoreFromUrlToken(): Promise<RestoreFromTokenResponse | null>;
  /**
   * Get the current active ticket ID
   * Returns null if no conversation has been started yet
   */
  getCurrentTicketId(): string | null;
  /**
   * Get the widget session ID (persistent browser identifier)
   * This ID is used for access control and stays the same across page loads
   */
  getWidgetSessionId(): string;
  private _identityFields;
  setIdentity(): void;
  clearIdentity(): void;
  private _resetConversationState;
  private _loadTicketsAndReconcileView;
  /**
   * Clean up the widget
   */
  destroy(): void;
  /**
   * Reset all conversation data and destroy the widget.
   * Called on posthog.reset() to start fresh.
   */
  reset(): void;
  /**
   * Render the widget to the DOM
   */
  private _renderWidget;
}
/**
 * Initialize the conversations widget.
 * This is the entry point called from the lazy-loaded bundle.
 *
 * Singleton guard: only one ConversationsManager per page. The toolbar's
 * internal PostHog instance is excluded upstream (see loadIfEnabled), so
 * this always belongs to the customer's main instance.
 */
declare function initConversations(config: ConversationsRemoteConfig, posthog: PostHog): ConversationsManager;
//#endregion
export { initConversations as default };