#!/usr/bin/env python3
"""Send and receive one message over TLS using a temporary RabbitMQ queue."""

import getpass
import os
import ssl
import sys

import pika


def connection_parameters():
    """Read non-secret settings and prompt for the RabbitMQ password."""
    names = ("RABBITMQ_HOST", "RABBITMQ_USER", "RABBITMQ_VHOST")
    missing = [name for name in names if not os.environ.get(name)]
    if missing:
        raise ValueError("Set these variables first: " + ", ".join(missing))

    host = os.environ["RABBITMQ_HOST"]
    if "://" in host or "/" in host or host.endswith(".invalid"):
        raise ValueError("RABBITMQ_HOST must contain your broker's hostname only.")
    port = int(os.environ.get("RABBITMQ_PORT", "5671"))
    if not 1 <= port <= 65535:
        raise ValueError("RABBITMQ_PORT must be between 1 and 65535.")

    context = ssl.create_default_context()
    password = getpass.getpass("RabbitMQ password: ")
    return pika.ConnectionParameters(
        host=host,
        port=port,
        virtual_host=os.environ["RABBITMQ_VHOST"],
        credentials=pika.PlainCredentials(os.environ["RABBITMQ_USER"], password),
        ssl_options=pika.SSLOptions(context, host),
        heartbeat=60,
        socket_timeout=10,
        stack_timeout=30,
        blocked_connection_timeout=30,
    )


def main():
    connection = pika.BlockingConnection(connection_parameters())
    try:
        channel = connection.channel()
        declared = channel.queue_declare(
            queue="",
            durable=False,
            exclusive=True,
            auto_delete=True,
            arguments={"x-queue-type": "classic"},
        )
        queue_name = declared.method.queue
        message = b"Hello from Message Broker"

        channel.confirm_delivery()
        channel.basic_publish(
            exchange="",
            routing_key=queue_name,
            body=message,
            mandatory=True,
        )
        print("Sent:", message.decode("utf-8"))

        method, properties, body = channel.basic_get(
            queue=queue_name, auto_ack=False
        )
        if method is None or body != message:
            raise RuntimeError("The expected test message was not received.")

        channel.basic_ack(delivery_tag=method.delivery_tag)
        print("Received:", body.decode("utf-8"))
        print("Connection test passed.")
    finally:
        if connection.is_open:
            connection.close()


if __name__ == "__main__":
    try:
        main()
    except (ValueError, RuntimeError) as error:
        print(str(error), file=sys.stderr)
        sys.exit(1)
    except (pika.exceptions.AMQPError, OSError, EOFError) as error:
        print(
            f"Connection test failed ({type(error).__name__}). "
            "Check the endpoint, TLS, allowed IP ranges, credentials, "
            "and vhost permissions.",
            file=sys.stderr,
        )
        sys.exit(1)
    except KeyboardInterrupt:
        print("Connection test interrupted.", file=sys.stderr)
        sys.exit(130)
