import json
import logging
import threading
import uuid
import pika
from pika.delivery_mode import DeliveryMode

from rabbitmq_starter import MQConfig, MQConnection


class MQProducer:
    """RabbitMQ生产者类
    
    负责发送普通消息和延迟消息到RabbitMQ队列
    """
    config = MQConfig()
    _connection = None
    _channel = None
    _lock = threading.Lock()
    max_retry = 3

    @staticmethod
    def _get_channel():
        if MQProducer._channel is None or MQProducer._channel.is_closed:
            with MQProducer._lock:
                if MQProducer._channel is None or MQProducer._channel.is_closed:
                    mq = MQConnection(MQProducer.config)
                    mq.connect()
                    MQProducer._connection = mq.connection
                    MQProducer._channel = mq.connection.channel()
                    logging.info(f"Created channel={MQProducer._channel.channel_number}")

        return MQProducer._channel

    @staticmethod
    def send(queue, message):

        """发送普通消息
        
        Args:
            queue: 队列名称
            message: 消息内容（字典）
            
        Returns:
            str: 消息ID
        """

        for i in range(MQProducer.max_retry):
            try:
                message_id = str(uuid.uuid4())  # 生成唯一消息ID
                # MQProducer.mq_connection.channel.queue_declare(queue=queue, durable=True)
                # 发送消息
                MQProducer._get_channel().basic_publish(
                    exchange="",  # 默认交换机
                    routing_key=queue,  # 队列名称作为路由键
                    body=json.dumps(message),  # 消息体
                    properties=pika.BasicProperties(
                        message_id=message_id,  # 消息ID
                        delivery_mode=DeliveryMode.Persistent  # 持久化消息
                    )
                )
                logging.info(f"message sent successfully with ID: {message_id},body:{json.dumps(message)}")

                return message_id
            except Exception as e:
                if i == MQProducer.max_retry - 1:
                    raise Exception(f"message sent error:{e}")
        raise Exception("message sent error")

    @staticmethod
    def send_delay(queue, message, delay_ms):
        """发送延迟消息
        
        Args:
            queue: 队列名称
            message: 消息内容（字典）
            delay_ms: 延迟时间（毫秒）
            
        Returns:
            str: 消息ID
        """
        for i in range(MQProducer.max_retry):
            try:
                message_id = str(uuid.uuid4())  # 生成唯一消息ID

                # 确保延迟交换机和队列之间已经绑定
                logging.debug(f"Binding queue {queue} to delay exchange {MQProducer.config.delay_exchange}...")
                MQProducer._get_channel().queue_bind(
                    queue=queue,
                    exchange=MQProducer.config.delay_exchange,
                    routing_key=queue
                )
                logging.debug(f"Queue {queue} bound to delay exchange {MQProducer.config.delay_exchange} successfully")

                logging.debug(f"Sending delay message to queue: {queue}, message: {message}, delay: {delay_ms}ms")
                # 发送延迟消息
                MQProducer._get_channel().basic_publish(
                    exchange=MQProducer.config.delay_exchange,  # 延迟交换机
                    routing_key=queue,  # 队列名称作为路由键
                    body=json.dumps(message),  # 消息体
                    properties=pika.BasicProperties(
                        headers={"x-delay": delay_ms},  # 延迟时间
                        message_id=message_id,  # 消息ID
                        delivery_mode=DeliveryMode.Persistent  # 持久化消息
                    )
                )
                logging.info(f"Delay message sent successfully with ID: {message_id},body:{json.dumps(message)}")

                return message_id

            except Exception as e:
                if i == MQProducer.max_retry - 1:
                    raise Exception(f"message sent error:{e}")
        raise Exception("message sent error")
