{%- import "util.jinja.include" as util -%}
// This code was generated by the xRegistry tool.
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.

import * as rhea from 'rhea';

/**
 * A wrapper for the rhea AMQP consumer that processes messages
 */
export class AmqpConsumer {
    private connection: rhea.Connection | null = null;
    private receiver: rhea.Receiver | null = null;
    
    /**
     * Message handler for processing messages
     */
    public processMessage?: (message: rhea.Message) => Promise<void>;
    
    /**
     * Error handler
     */
    public processError?: (error: Error) => Promise<void>;
    
    /**
     * Create a new AmqpConsumer
     * @param host The AMQP host
     * @param port The AMQP port
     * @param address The AMQP address (queue or topic)
     * @param username Optional username for authentication
     * @param password Optional password for authentication
     */
    constructor(
        private host: string,
        private port: number = 5672,
        private address: string,
        private username?: string,
        private password?: string
    ) {}
    
    /**
     * Start consuming messages
     */
    async start(): Promise<void> {
        return new Promise((resolve, reject) => {
            const connectionOptions: rhea.ConnectionOptions = {
                host: this.host,
                port: this.port,
                reconnect: true
            };
            
            if (this.username && this.password) {
                connectionOptions.username = this.username;
                connectionOptions.password = this.password;
            }
            
            // Type assertion for rhea library's missing type definition
            this.connection = (rhea as unknown as { connect(opts: rhea.ConnectionOptions): rhea.Connection }).connect(connectionOptions);
            
            this.connection!.on('connection_open', () => {
                this.receiver = this.connection!.open_receiver({
                    source: { address: this.address },
                    autoaccept: false,
                    credit_window: 10
                });
                
                resolve();
            });
            
            this.connection!.on('connection_error', (context) => {
                const error = context.error || new Error('Connection error');
                console.error('AMQP connection error:', error);
                if (this.processError) {
                    this.processError(error);
                }
                reject(error);
            });
            
            this.connection!.on('message', async (context: rhea.EventContext) => {
                const message = context.message;
                if (!message || !context.delivery) {
                    return;
                }
                
                try {
                    if (this.processMessage) {
                        await this.processMessage(message);
                    }
                    
                    // Accept the message
                    context.delivery!.accept();
                } catch (error) {
                    console.error('Error processing message:', error);
                    
                    // Reject the message
                    context.delivery!.reject();
                    
                    if (this.processError && error instanceof Error) {
                        await this.processError(error);
                    }
                }
            });
        });
    }
    
    /**
     * Stop consuming messages
     */
    async stop(): Promise<void> {
        if (this.receiver) {
            this.receiver.close();
            this.receiver = null;
        }
        
        if (this.connection) {
            this.connection.close();
            this.connection = null;
        }
    }
}
