import { HookifiedOptions, Hookified } from 'hookified';

/**
 * Message interface for the message provider
 * @template T - The type of the message data
 */
type Message<T = any> = {
    /**
     * Unique identifier for the message
     * @type {string}
     */
    id: string;
    /**
     * the provider that passed the message
     */
    providerId?: string;
    /**
     * The data of the message
     * @type {<T = any>}
     */
    data: T;
    /**
     * Timestamp of when the message was created
     * @type {number}
     */
    timestamp?: number;
    /**
     * Headers for additional metadata
     * @type {Record<string, string>}
     */
    headers?: Record<string, string>;
};
type TopicHandler = {
    id?: string;
    handler: (message: Message) => Promise<void>;
};
/**
 * MessageProvider interface for the message provider
 */
type MessageProvider = {
    /**
     * The id of the message provider. Use primary when multiple providers
     * are used.
     */
    id: string;
    /**
     * Array of handlers for message processing
     * @type {Map<string, Array<TopicHandler>>}
     */
    subscriptions: Map<string, TopicHandler[]>;
    /**
     * Plublish a message to a topic / queue. This is used to send messages to subscribers.
     * @param topic - The topic or queue to publish the message to
     * @param message - The message to be published
     * @returns {Promise<void>}
     */
    publish(topic: string, message: Omit<Message, "providerId">): Promise<void>;
    /**
     * Subscribe to a topic / queue. This is used to receive messages from the provider.
     * @param {TopicHandler} subscription - The topic or queue to subscribe to
     * @returns {Promise<void>}
     */
    subscribe(topic: string, handler: TopicHandler): Promise<void>;
    /**
     * Remove subscription to a topic / queue.
     * @param topic - The topic or queue to unsubscribe from
     * @param id - Optional unique identifier for the subscription to remove. If not provided, it will remove all subscriptions for the topic.
     * @returns {Promise<void>}
     */
    unsubscribe(topic: string, id?: string): Promise<void>;
    /**
     * Unsubscribe from a topic / queue. This is used to stop receiving messages from the provider.
     * @returns {Promise<void>}
     */
    disconnect(): Promise<void>;
};
/**
 * Task interface for the task provider
 * @template T - The type of the task data
 */
type Task<T = any> = {
    /**
     * Unique identifier for the task
     * @type {string}
     */
    id: string;
    /**
     * The data of the task
     * @type {<T = any>}
     */
    data: T;
    /**
     * Timestamp of when the task was created (milliseconds since epoch)
     * Set automatically by provider if not provided based on Date.now()
     * @type {number}
     */
    timestamp?: number;
    /**
     * Scheduled time for delayed task execution (milliseconds since epoch)
     * If set, task won't be processed until this time
     * @type {number}
     */
    scheduledAt?: number;
    /**
     * Headers for additional metadata
     * @type {Record<string, string>}
     */
    headers?: Record<string, string>;
    /**
     * Priority of the task (higher numbers = higher priority)
     * @type {number}
     * @default 0
     */
    priority?: number;
    /**
     * Maximum number of retry attempts
     * If undefined, uses provider default
     * @type {number}
     */
    maxRetries?: number;
    /**
     * Maximum processing time in milliseconds before task times out
     * If not set, uses provider default
     * @type {number}
     */
    timeout?: number;
};
/**
 * Task type for enqueueing tasks
 * Omits fields that are automatically generated by the provider
 * The provider will assign the id and timestamp when the task is enqueued
 */
type EnqueueTask = Omit<Task, "id" | "timestamp">;
/**
 * Context provided to task handlers for acknowledgment and task control
 * Allows handlers to acknowledge, reject, or extend processing time for tasks
 */
type TaskContext = {
    /**
     * Acknowledge successful task completion
     * Removes the task from the queue and marks it as completed
     * @returns {Promise<void>}
     */
    ack: () => Promise<void>;
    /**
     * Reject the task with explicit requeue control
     * @param requeue - If true, requeue for retry. If false, send to dead-letter queue. Defaults to true.
     * @returns {Promise<void>}
     */
    reject: (requeue?: boolean) => Promise<void>;
    /**
     * Extend the visibility timeout / processing deadline
     * Prevents task from being redelivered to another consumer while still processing
     * Useful for long-running tasks that need more time
     * @param ttl - Additional time to live in milliseconds
     * @returns {Promise<void>}
     */
    extend: (ttl: number) => Promise<void>;
    /**
     * Metadata about the current task execution
     * Provides context for retry logic and deadline management
     */
    metadata: {
        /**
         * Current retry attempt (0 = first attempt)
         * @type {number}
         */
        attempt: number;
        /**
         * Maximum retries allowed for this task
         * @type {number}
         */
        maxRetries: number;
    };
};
/**
 * Handler configuration for processing tasks from a queue
 * Defines how tasks should be processed and provides options for error handling
 */
type TaskHandler = {
    /**
     * Optional unique identifier for this handler
     * Used to identify and unsubscribe specific handlers
     * @type {string}
     */
    id?: string;
    /**
     * The handler function to process tasks
     * Called for each task dequeued from the queue
     * @param task - The task to process
     * @param context - Context for acknowledging, rejecting, or extending the task
     * @returns {Promise<void>}
     */
    handler: (task: Task, context: TaskContext) => Promise<void>;
};
/**
 * TaskProvider interface for task queue management
 * Handles enqueueing, dequeueing, and lifecycle management of tasks
 * Implementations should provide reliable task delivery and acknowledgment
 */
type TaskProvider = {
    /**
     * Unique identifier for this provider instance
     * Used to distinguish between multiple providers
     * @type {string}
     */
    id: string;
    /**
     * Default timeout for task processing in milliseconds
     * Can be overridden per task or per handler
     * @type {number}
     */
    timeout: number;
    /**
     * Default maximum number of retry attempts
     * Can be overridden per task
     * @type {number}
     */
    retries: number;
    /**
     * Name of the dead-letter queue for failed tasks
     * If not provided, dead-letter functionality is disabled
     * @type {string}
     */
    deadLetterQueue?: string;
    /**
     * Map of queue names to their registered handlers
     * Tracks all active handlers for each queue
     * @type {Map<string, TaskHandler[]>}
     */
    taskHandlers: Map<string, TaskHandler[]>;
    /**
     * Enqueue a task to a specific queue for processing
     * The task will be delivered to registered handlers for that queue
     * @param queue - The queue name to enqueue the task to
     * @param task - The task to be enqueued
     * @returns {Promise<string>} - the id of the task being queued
     */
    enqueue(queue: string, task: EnqueueTask): Promise<string>;
    /**
     * Register a handler to process tasks from a specific queue
     * The handler will be called for each task dequeued from the queue
     * @param queue - The queue name to dequeue tasks from
     * @param handler - The handler configuration for processing tasks
     * @returns {Promise<void>}
     */
    dequeue(queue: string, handler: TaskHandler): Promise<void>;
    /**
     * Unsubscribe a handler from a queue
     * Stops the handler from receiving new tasks
     * @param queue - The queue name to unsubscribe from
     * @param id - Optional handler ID. If not provided, removes all handlers for the queue
     * @returns {Promise<void>}
     */
    unsubscribe(queue: string, id?: string): Promise<void>;
    /**
     * Disconnect and clean up the provider
     * Stops receiving tasks, closes connections, and releases resources
     * Should be called before application shutdown
     * @returns {Promise<void>}
     */
    disconnect(): Promise<void>;
};

/**
 * Configuration options for the memory message provider.
 */
type MemoryMessageProviderOptions = {
    /**
     * The unique identifier for this provider instance.
     * @default "@qified/memory"
     */
    id?: string;
};
/**
 * In-memory message provider for testing and simple use cases.
 * Messages are stored and delivered synchronously in memory without persistence.
 */
declare class MemoryMessageProvider implements MessageProvider {
    private _subscriptions;
    private _id;
    /**
     * Creates an instance of MemoryMessageProvider.
     * @param {MemoryMessageProviderOptions} options - Optional configuration for the provider.
     */
    constructor(options?: MemoryMessageProviderOptions);
    /**
     * Gets the provider ID for the memory message provider.
     * @returns {string} The provider ID.
     */
    get id(): string;
    /**
     * Sets the provider ID for the memory message provider.
     * @param {string} id The new provider ID.
     */
    set id(id: string);
    /**
     * Gets the subscriptions map for all topics.
     * @returns {Map<string, TopicHandler[]>} The subscriptions map.
     */
    get subscriptions(): Map<string, TopicHandler[]>;
    /**
     * Sets the subscriptions map.
     * @param {Map<string, TopicHandler[]>} value The new subscriptions map.
     */
    set subscriptions(value: Map<string, TopicHandler[]>);
    /**
     * Publishes a message to a specified topic.
     * All handlers subscribed to the topic will be called synchronously in order.
     * @param {string} topic The topic to publish the message to.
     * @param {Message} message The message to publish.
     * @returns {Promise<void>} A promise that resolves when all handlers have been called.
     */
    publish(topic: string, message: Omit<Message, "providerId">): Promise<void>;
    /**
     * Subscribes to a specified topic.
     * @param {string} topic The topic to subscribe to.
     * @param {TopicHandler} handler The handler to process incoming messages.
     * @returns {Promise<void>} A promise that resolves when the subscription is complete.
     */
    subscribe(topic: string, handler: TopicHandler): Promise<void>;
    /**
     * Unsubscribes from a specified topic.
     * If an ID is provided, only the handler with that ID is removed.
     * If no ID is provided, all handlers for the topic are removed.
     * @param {string} topic The topic to unsubscribe from.
     * @param {string} [id] Optional identifier for the subscription to remove.
     * @returns {Promise<void>} A promise that resolves when the unsubscription is complete.
     */
    unsubscribe(topic: string, id?: string): Promise<void>;
    /**
     * Disconnects and clears all subscriptions.
     * @returns {Promise<void>} A promise that resolves when the disconnection is complete.
     */
    disconnect(): Promise<void>;
}

/**
 * Standard events emitted by Qified.
 */
declare enum QifiedEvents {
    error = "error",
    info = "info",
    warn = "warn",
    publish = "publish",
    subscribe = "subscribe",
    unsubscribe = "unsubscribe",
    disconnect = "disconnect"
}
type QifiedOptions = {
    /**
     * The message providers to use.
     */
    messageProviders?: MessageProvider | MessageProvider[];
    /**
     * The task providers to use.
     */
    taskProviders?: TaskProvider[];
} & HookifiedOptions;
declare class Qified extends Hookified {
    private _messageProviders;
    /**
     * Creates an instance of Qified.
     * @param {QifiedOptions} options - Optional configuration for Qified.
     */
    constructor(options?: QifiedOptions);
    /**
     * Gets or sets the message providers.
     * @returns {MessageProvider[]} The array of message providers.
     */
    get messageProviders(): MessageProvider[];
    /**
     * Sets the message providers.
     * @param {MessageProvider[]} providers - The array of message providers to set.
     */
    set messageProviders(providers: MessageProvider[]);
    /**
     * Subscribes to a topic. If you have multiple message providers, it will subscribe to the topic on all of them.
     * @param {string} topic - The topic to subscribe to.
     * @param {TopicHandler} handler - The handler to call when a message is published to the topic.
     */
    subscribe(topic: string, handler: TopicHandler): Promise<void>;
    /**
     * Publishes a message to a topic. If you have multiple message providers, it will publish the message to all of them.
     * @param {string} topic - The topic to publish to.
     * @param {Message} message - The message to publish.
     */
    publish(topic: string, message: Omit<Message, "providerId">): Promise<void>;
    /**
     * Unsubscribes from a topic. If you have multiple message providers, it will unsubscribe from the topic on all of them.
     * If an ID is provided, it will unsubscribe only that handler. If no ID is provided, it will unsubscribe all handlers for the topic.
     * @param topic - The topic to unsubscribe from.
     * @param id - The optional ID of the handler to unsubscribe. If not provided, all handlers for the topic will be unsubscribed.
     */
    unsubscribe(topic: string, id?: string): Promise<void>;
    /**
     * Disconnects from all providers.
     * This method will call the `disconnect` method on each message provider.
     */
    disconnect(): Promise<void>;
}

export { MemoryMessageProvider, type Message, type MessageProvider, Qified, QifiedEvents, type QifiedOptions, type TaskProvider, type TopicHandler };
