"""
Example Consumer for a queue


In this example we create an queue consumer that gets one message at a time, and processes
it using a processor. To emulate some of the complexities, we randomly fail processing and adding
delays to processing.

This example is similar to consumer.py but uses RedisSMQConsumerThread which is a versioin 
of RedisSMQConsumer that extends the Thread class
"""
import argparse
import logging
import random
import sys
import time

from rsmq.consumer import RedisSMQConsumerThread


LOG = logging.getLogger("Consumer")


class Processor(object):
    """Dummy processor class to fake complexity of a real processor"""

    def __init__(self, delay, success_rate):
        self.delay = delay
        self.success_rate = success_rate

    def random_result(self):
        """
        Produce a random boolean which is True "success_rate" percent of the time

        random.random() produces a float in range [0.0, 1.0)
        """
        return random.random() < self.success_rate

    def process(self, id, message, rc, ts):
        """Actual method that processes the message"""
        LOG.info(
            "Got message: id: %s, retry count: %s, ts: %s, msg: %s (%s)"
            % (id, rc, ts, message, type(message))
        )
        result = self.random_result()
        delay = self.delay
        if delay > 0:
            # Add occasional long delay
            # if random.randint(0, 10) == 0:
            #    delay = 60
            LOG.info("Processing message: %s for %s seconds", id, delay)
            time.sleep(delay)
        # LOG.info("Random Result: %s", "Success" if result else "Failure")
        return result


def consume(consumer, long_qname, exit_after):
    """Example of consuming using a thread"""
    LOG.info("Starting consumption on queue: %s", long_qname)
    consumer.start()
    end = time.time() + exit_after if exit_after else 0
    while True:
        if exit_after and time.time() > end:
            LOG.info("Attempting to stop the consumer...")
            consumer.stop(15)
            break
    LOG.info(
        "Exited queue consumer for '%s'. Thread is %s",
        long_qname,
        ("running" if consumer.is_alive() else "stopped"),
    )


def probablity(x):
    """An arg validator that Require a float number between 0.0 and 1.0"""
    x = float(x)
    if not (0.0 <= x <= 1.0):
        raise argparse.ArgumentTypeError("%r not in range [0.0, 1.0]" % (x,))
    return x


def main(argv=None):
    if argv is None:
        argv = sys.argv
    """ Parse args and run producer """
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-q",
        "--queue",
        dest="queue",
        action="store",
        default="queue",
        help="queue name [default: %(default)s]",
    )
    parser.add_argument(
        "-n",
        "--namespace",
        dest="ns",
        action="store",
        default="test",
        help="queue namespace [default: %(default)s]",
    )

    parser.add_argument(
        "-r",
        "--success_rate",
        dest="success_rate",
        action="store",
        type=probablity,
        default=1.0,
        help="Probability of success when processing messages."
        + "1.0 means all are successful, 0.0 means all fail"
        + "[default: %(default)s]",
    )

    parser.add_argument(
        "-e",
        "--empty_delay",
        dest="empty_queue_delay",
        type=float,
        default=4.0,
        help="delay in seconds when queue is empty[default: %(default)s]",
    )

    parser.add_argument(
        "-d",
        "--delay",
        dest="delay",
        type=float,
        default=2.0,
        help="additional delay in seconds, during consumption[default: %(default)s]",
    )

    parser.add_argument(
        "-x",
        "--exit_after",
        dest="exit_after",
        type=float,
        default=0.0,
        help="If set, exit after this many seconds[default: %(default)s]",
    )

    parser.add_argument(
        "-v",
        "--visibility_timeout",
        dest="vt",
        type=int,
        default=None,
        help="Visibility Timeout[default: %(default)s]",
    )

    parser.add_argument(
        "--no-trace",
        dest="trace",
        action="store_false",
        default=True,
        help="If set, hide trace messages",
    )

    parser.add_argument(
        "-D",
        "--decode",
        dest="decode",
        action="store_true",
        default=False,
        help="If set, decode messages from JSON",
    )

    parser.add_argument(
        "-H", dest="host", default="127.0.0.1", help="Redis Host [default: %(default)s]"
    )
    parser.add_argument(
        "-P",
        dest="port",
        type=int,
        default=6379,
        help="Redis Port [default: %(default)s]",
    )

    # Parse command line args`
    args = parser.parse_args()

    # Create Processor
    processor = Processor(delay=args.delay, success_rate=args.success_rate)

    # Create RedisSMQ queue consumer controller
    LOG.info(
        "Creating RedisSMQ Consumer Controller for redis at %s:%s, using queue: %s:%s",
        args.host,
        args.port,
        args.ns,
        args.queue,
    )
    rsqm_consumer = RedisSMQConsumerThread(
        qname=args.queue,
        processor=processor.process,
        host=args.host,
        port=args.port,
        ns=args.ns,
        vt=args.vt,
        empty_queue_delay=args.empty_queue_delay,
        decode=args.decode,
        trace=args.trace,
    )

    # Start Consumption
    consume(rsqm_consumer, "%s:%s" % (args.ns, args.queue), args.exit_after)


if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG)
    main(sys.argv)
