```python
#!/usr/bin/env python3
"""Thread-safe logging demo using QueueHandler and QueueListener.

This script shows a practical, vendor-neutral pattern for decoupling log
production from log emission in multi-threaded Python applications.

Features:
- Queue-based logging configuration
- Optional worker thread demo
- Safe argparse interface
- No hard-coded secrets or environment-specific endpoints
- Clean shutdown that drains queued log records

Usage examples:
  python queue_logging_demo.py
  python queue_logging_demo.py --workers 8 --messages 20 --level DEBUG
  python queue_logging_demo.py --log-file app.log --queue-size 1000
"""

from __future__ import annotations

import argparse
import logging
import queue
import sys
import threading
import time
from logging.handlers import QueueHandler, QueueListener
from typing import Optional


def positive_int(value: str) -> int:
    """Validate that an argument is a positive integer."""
    try:
        parsed = int(value)
    except ValueError as exc:
        raise argparse.ArgumentTypeError(f"invalid integer value: {value!r}") from exc
    if parsed <= 0:
        raise argparse.ArgumentTypeError("value must be greater than zero")
    return parsed


def non_negative_int(value: str) -> int:
    """Validate that an argument is a non-negative integer."""
    try:
        parsed = int(value)
    except ValueError as exc:
        raise argparse.ArgumentTypeError(f"invalid integer value: {value!r}") from exc
    if parsed < 0:
        raise argparse.ArgumentTypeError("value must be zero or greater")
    return parsed


def build_formatter() -> logging.Formatter:
    """Create a consistent log formatter for downstream handlers."""
    return logging.Formatter(
        fmt="%(asctime)s %(levelname)s %(threadName)s %(name)s: %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )


def build_handler(log_file: Optional[str]) -> logging.Handler:
    """Create the real output handler used by the listener.

    If log_file is None, logs are written to stderr via StreamHandler.
    """
    if log_file:
        handler: logging.Handler = logging.FileHandler(log_file, encoding="utf-8")
    else:
        handler = logging.StreamHandler(sys.stderr)
    handler.setFormatter(build_formatter())
    return handler


def configure_queue_logging(
    *,
    level: str,
    log_file: Optional[str],
    queue_size: int,
) -> tuple[QueueListener, logging.Logger, queue.Queue]:
    """Configure root logging to route records through a queue."""
    log_queue: queue.Queue = queue.Queue(maxsize=queue_size)
    queue_handler = QueueHandler(log_queue)

    output_handler = build_handler(log_file)
    listener = QueueListener(log_queue, output_handler, respect_handler_level=True)

    root_logger = logging.getLogger()
    root_logger.setLevel(getattr(logging, level.upper(), logging.INFO))
    root_logger.handlers.clear()
    root_logger.addHandler(queue_handler)
    root_logger.propagate = False

    return listener, root_logger, log_queue


def worker_task(worker_id: int, messages: int, delay: float) -> None:
    """Emit a predictable set of log messages from one worker thread."""
    logger = logging.getLogger(f"worker-{worker_id}")
    for i in range(messages):
        logger.info("processing item %d of %d", i + 1, messages)
        if delay > 0:
            time.sleep(delay)
    logger.info("worker %d completed", worker_id)


def run_demo(workers: int, messages: int, delay: float) -> None:
    """Start worker threads to demonstrate queue-based logging."""
    threads: list[threading.Thread] = []
    for worker_id in range(1, workers + 1):
        thread = threading.Thread(
            target=worker_task,
            name=f"worker-thread-{worker_id}",
            args=(worker_id, messages, delay),
            daemon=False,
        )
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()


def parse_args() -> argparse.Namespace:
    """Parse command-line arguments."""
    parser = argparse.ArgumentParser(
        description="Demonstrate Python thread-safe logging with QueueHandler and QueueListener."
    )
    parser.add_argument(
        "--workers",
        type=positive_int,
        default=4,
        help="number of worker threads to start (default: 4)",
    )
    parser.add_argument(
        "--messages",
        type=positive_int,
        default=10,
        help="log messages per worker thread (default: 10)",
    )
    parser.add_argument(
        "--delay",
        type=float,
        default=0.05,
        help="seconds to sleep between worker log messages (default: 0.05)",
    )
    parser.add_argument(
        "--level",
        type=str,
        default="INFO",
        choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
        help="root logging level (default: INFO)",
    )
    parser.add_argument(
        "--log-file",
        type=str,
        default=None,
        help="optional path to a log file; defaults to stderr",
    )
    parser.add_argument(
        "--queue-size",
        type=non_negative_int,
        default=0,
        help="queue max size; use 0 for unbounded (default: 0)",
    )
    parser.add_argument(
        "--no-demo",
        action="store_true",
        help="configure logging and exit without starting worker threads",
    )
    return parser.parse_args()


def main() -> int:
    args = parse_args()

    if args.delay < 0:
        print("--delay must be zero or greater", file=sys.stderr)
        return 2

    listener: Optional[QueueListener] = None
    try:
        listener, _root_logger, _log_queue = configure_queue_logging(
            level=args.level,
            log_file=args.log_file,
            queue_size=args.queue_size,
        )
        listener.start()

        logger = logging.getLogger(__name__)
        logger.info("queue-based logging configured successfully")

        if not args.no_demo:
            run_demo(args.workers, args.messages, args.delay)
            logger.info("all worker threads completed")
        else:
            logger.info("demo disabled; exiting after configuration")

        return 0
    finally:
        # Stop the listener after worker threads finish so queued records are drained.
        if listener is not None:
            listener.stop()


if __name__ == "__main__":
    raise SystemExit(main())
```