import logging
import asyncio
import random
from ..abc.source import TriggerSource


L = logging.getLogger(__name__)


class RandomSource(TriggerSource):
    """
    `RandomSource` is mostly meant for testing. It
    generates n (specified in `Config` as `number`, default is 1000) events per trigger fire.

    There can be 2 options of usage:
    a) User provides `choice` as an array of values to choose randomly;
    b) The random integer between `Config['lower_bound']` and `Config['upper_bound']`

    If `field` from `Config` is not an empty string, the random source generates dictionary
    event `{`field`: `generated value`}`. Otherwise it's a random number.
    """

    ConfigDefaults = {
        "field": "",
        "number": 1000,
        "lower_bound": 0,
        "upper_bound": 1000,
        "event_idle_time": 0.01,
        "events_till_idle": 10000,
    }

    def __init__(self, app, pipeline, choice=None, id=None, config=None):
        super().__init__(app, pipeline, id=id, config=config)
        self.Number = int(self.Config["number"])
        self.LowerBound = int(self.Config["lower_bound"])
        self.UpperBound = int(self.Config["upper_bound"])
        self.EventIdleTime = float(self.Config["event_idle_time"])
        self.EventsTillIdle = int(self.Config["events_till_idle"])
        self.EventCounter = 0
        self.Choice = None
        self.Field = None
        if choice is not None:
            self.Choice = choice

        if self.Config["field"] != "":
            self.Field = self.Config["field"]

    def generate_random(self):
        """
        Override this method to generate differently
        """
        if self.Choice is not None:
            if self.Field is not None:
                return {self.Field: random.choice(self.Choice)}

            return random.choice(self.Choice)
        else:
            if self.Field is not None:
                return {self.Field: random.randint(self.LowerBound, self.UpperBound)}

            return random.randint(self.LowerBound, self.UpperBound)

    async def cycle(self):
        for i in range(0, self.Number):
            event = self.generate_random()
            await self.process(event)
            if self.EventCounter >= self.EventsTillIdle:
                await asyncio.sleep(self.EventIdleTime)
                self.EventCounter = 0

            self.EventCounter += 1
