import type { BrokerAckPolicy, BrokerRetention } from "./contract.js";
import type {
    BrokerEffectivelyOnceGuarantee,
    BrokerEffectivelyOnceNoGuarantee,
    BrokerEffectivelyOnceNone,
} from "./effectively-once.js";

/**
 * Point-to-point without any guarantees that the message will be delivered to the subscriber
 * (i.e., a single replica of the same service).
 *
 * - Exactly one active subscriber receives the message.
 * - `at-most-once`; no broker persistence/dedupe.
 *
 * Example use cases:
 * - Send a push notification to a particular device
 *
 * Example: Use NATS Core instead of JetStream (`at-most-once`).
 */
type BrokerPointToPointNoGuarantee = {
    type: "point-to-point+no-guarantee";
    /**
     * To make sure the message is delivered to one subscriber, messages are published to a queue first
     * and then consumed from the queue by a single subscriber.
     *
     * Use `{purpose}` as placeholder for the purpose of the durable subscription.
     * Use `{durable}` as placeholder for the durable name (the service/consumer name).
     *
     * @default Automatically generated with `{durable}` and `{purpose}` placeholder
     * @example
     * ```typescript
     * queue: "q_orders_{durable}_{purpose}_v1" // {durable} and {purpose} will be replaced at subscription time
     * ```
     */
    queue?: string;
} & (BrokerEffectivelyOnceNone | BrokerEffectivelyOnceNoGuarantee);

/**
 * Point-to-point with a guarantee that the message will be delivered to the subscriber
 * (i.e., a single replica of the same service).
 *
 * - Exactly one active subscriber receives the message.
 * - `at-least-once`; broker persistence/dedupe.
 *
 * Example use cases:
 * - Send a order-finished event and listen to it to update the inventory and send a confirmation email
 *
 * Example: Use JetStream instead of NATS Core (`at-least-once`).
 */
type BrokerPointToPointGuarantee = {
    type: "point-to-point+guarantee";
    /**
     * Name of the stream to publish the message to (bridge between publisher and subscriber to be able
     * to replay the message and hold it for a while).
     *
     * @default Automatically generated
     */
    stream?: string;
    /**
     * Name of the durable subscription to use for the stream.
     *
     * Use `{purpose}` as placeholder for the purpose of the durable subscription.
     * Use `{durable}` as placeholder for the durable name (the service/consumer name).
     *
     * @default Automatically generated
     */
    durable?: string;
    /**
     * Time to wait for an ack from the subscriber until redelivered.
     */
    ackWaitMs?: number;
    /**
     * Maximum number of times to redeliver the message to the subscriber until it is considered failed.
     */
    maxDeliver?: number;
    /**
     * Defines the maximum number of messages, without acknowledgment, that can be outstanding. Once this limit
     * is reached, message delivery will be suspended. This limit applies across all of the consumer's bound
     * subscriptions. A value of -1 means there can be any number of pending acknowledgments (i.e., no flow control).
     *
     * Setting `maxAckPending` to `1` does not actually provide "effectively-once" or "exactly-once" delivery semantics.
     * Instead, it forces consumers to process messages one at a time (serial-processing), preventing parallelism and reducing throughput.
     * True "effectively-once" behavior is achieved by deduplicating messages using `Broker-Msg-Id` and by ensuring all
     * subscribers process actions idempotent, regardless of the `maxAckPending` value.
     *
     * @default 1000
     */
    maxAckPending?: number;
    /**
     * Dead Letter Queue configuration for messages that exceed maxDeliver attempts.
     *
     * When enabled, failed messages are moved to a separate stream for manual inspection
     * instead of being discarded. Useful for debugging and recovery.
     *
     * @default Enabled with sensible defaults
     * @example
     * ```typescript
     * deadLetterQueue: {
     *   enabled: true, // default: true
     *   stream: "ORDERS_DLQ", // optional, defaults to "{STREAM}_DLQ"
     *   ttlMs: 7 * 24 * 60 * 60 * 1000, // optional, defaults to 7 days
     *   durable: "ORDERS_DLQ_CONSUMER" // optional, defaults to "{STREAM}_DLQ_CONSUMER"
     * }
     * ```
     */
    deadLetterQueue?: {
        /**
         * Whether Dead Letter Queue is enabled for this contract.
         *
         * @default true
         */
        enabled?: boolean;
        /**
         * Name of the DLQ stream.
         *
         * @default Automatically generated "{originalStream}_DLQ"
         */
        stream?: string;
        /**
         * How long to keep messages in DLQ before discarding.
         * @default 7 days
         */
        ttlMs?: number;
        /**
         * Name of the DLQ durable.
         *
         * @default Automatically generated "{originalDurable}_dlq"
         */
        durable?: string;
    };
} & BrokerRetention &
    BrokerAckPolicy &
    BrokerEffectivelyOnceGuarantee;

export { type BrokerPointToPointNoGuarantee, type BrokerPointToPointGuarantee };
