"""Handle the audio streamer and controls it as we want it to be. It is used
to:

- generate config files and playlists;
- monitor Liquidsoap, logs and scheduled programs;
- cancels Diffusions that have an archive but could not have been played;
- run Liquidsoap
"""
from datetime import timezone
import time

from argparse import RawTextHelpFormatter

from django.core.management.base import BaseCommand
from django.utils import timezone as tz

from aircox.models import Station
from aircox_streamer.controllers import Monitor, Streamer


# force using UTC
tz.activate(timezone.UTC)


class Command(BaseCommand):
    help = __doc__

    def add_arguments(self, parser):
        parser.formatter_class = RawTextHelpFormatter
        group = parser.add_argument_group("actions")
        group.add_argument(
            "-c",
            "--config",
            action="store_true",
            help="generate configuration files for the stations",
        )
        group.add_argument(
            "-m",
            "--monitor",
            action="store_true",
            help="monitor the scheduled diffusions and log what happens",
        )
        group.add_argument(
            "-r",
            "--run",
            action="store_true",
            help="run the required applications for the stations",
        )

        group = parser.add_argument_group("options")
        group.add_argument(
            "-d",
            "--delay",
            type=int,
            default=1000,
            help="time to sleep in MILLISECONDS between two updates when we "
            "monitor. This influence the delay before a diffusion is "
            "launched.",
        )
        group.add_argument(
            "-s",
            "--station",
            type=str,
            action="append",
            help="name of the station to monitor instead of monitoring " "all stations",
        )
        group.add_argument(
            "-t",
            "--timeout",
            type=float,
            default=Monitor.cancel_timeout.total_seconds() / 60,
            help="time to wait in MINUTES before canceling a diffusion that " "should have ran but did not. ",
        )
        # TODO: sync-timeout, cancel-timeout

    def handle(self, *args, config=None, run=None, monitor=None, station=[], delay=1000, timeout=600, **options):
        stations = Station.objects.filter(name__in=station) if station else Station.objects.all()
        streamers = [Streamer(station) for station in stations]

        for streamer in streamers:
            if not streamer.outputs:
                raise RuntimeError("Streamer {} has no outputs".format(streamer.id))
            if config:
                streamer.make_config()
            if run:
                streamer.run_process()

        if monitor:
            delay = tz.timedelta(milliseconds=delay)
            timeout = tz.timedelta(minutes=timeout)
            monitors = [Monitor(streamer, delay, cancel_timeout=timeout) for streamer in streamers]

            while not run or streamer.is_running:
                for monitor in monitors:
                    monitor.monitor()
                time.sleep(delay.total_seconds())

        if run:
            for streamer in streamers:
                streamer.wait_process()
