import { env } from "@/lib/env";
import { logError } from "@/lib/logger";
import amqp from "amqplib";

class RabbitMQManager {
    private connection: amqp.ChannelModel | null = null;
    private channel: amqp.Channel | null = null;
    private isConnecting: boolean = false;
    private reconnectTimeout: NodeJS.Timeout | null = null;

    private readonly connectionString: string;

    constructor() {
        this.connectionString = env.GetString("PRODUCER_QUEUE_CONNECTION");
    }

    async connect(): Promise<amqp.Channel> {
        if (this.channel)
return this.channel;

        // Wait if already connecting to avoid race conditions
        if (this.isConnecting) {
            await new Promise(resolve => setTimeout(resolve, 100));
            return this.connect();
        }

        this.isConnecting = true;

        try {
            // logInfo("[RabbitMQ] Connecting...");
            this.connection = await amqp.connect(this.connectionString);

            this.connection.on("error", (err) => {
                logError(`[RabbitMQ] Connection error: ${err}`);
                this.handleDisconnect();
            });

            this.connection.on("close", () => {
                // logInfo("[RabbitMQ] Connection closed");
                this.handleDisconnect();
            });

            this.channel = await this.connection.createChannel();
            // logInfo("[RabbitMQ] Channel created successfully");

            this.isConnecting = false;
            return this.channel;
        } catch (error) {
            this.isConnecting = false;
            logError(`[RabbitMQ] Failed to connect: ${error}`);
            this.handleDisconnect();
            throw error;
        }
    }

    private handleDisconnect() {
        this.channel = null;
        this.connection = null;
        if (!this.reconnectTimeout) {
            // logInfo("[RabbitMQ] Scheduling reconnect in 5s...");
            this.reconnectTimeout = setTimeout(() => {
                this.reconnectTimeout = null;
                this.connect().catch(() => { });
            }, 5000);
        }
    }

    async getChannel(): Promise<amqp.Channel> {
        if (!this.channel) {
            return await this.connect();
        }
        return this.channel;
    }

    async close() {
        try {
            if (this.channel)
await this.channel.close();
            if (this.connection)
await this.connection.close();
        } catch (e) {
            logError(`[RabbitMQ] Error while closing: ${e}`);
        }
    }
}

// Singleton instance
export const rabbitMQ = new RabbitMQManager();
