import os
import tzlocal

from aircox.utils import to_seconds

from .metadata import Metadata, Request


__all__ = (
    "Source",
    "PlaylistSource",
    "QueueSource",
)

local_tz = tzlocal.get_localzone()


class Source(Metadata):
    controller = None
    """Parent controller."""
    id = None
    """Source id."""
    remaining = 0.0
    """Remaining time."""
    status = "stopped"

    @property
    def station(self):
        return self.controller.station

    def __init__(self, controller=None, id=None, *args, **kwargs):
        super().__init__(controller, *args, **kwargs)
        self.id = id

    def sync(self):
        """Synchronize what should be synchronized."""

    def fetch(self):
        try:
            data = self.controller.send(self.id, ".remaining")
            if data:
                self.remaining = float(data)
        except ValueError:
            self.remaining = None

        data = self.controller.send(self.id, ".get", parse=True)
        if data:
            self.validate(data if data and isinstance(data, dict) else {})

    def skip(self):
        """Skip the current source sound."""
        self.controller.send(self.id, ".skip")

    def restart(self):
        """Restart current sound."""
        # seek 10 hours back since there is not possibility to get current pos
        self.seek(-216000 * 10)

    def seek(self, n):
        """Seeks into the sound."""
        self.controller.send(self.id, ".seek ", str(n))


class PlaylistSource(Source):
    """Source handling playlists (program streams)"""

    path = None
    """Path to playlist."""
    program = None
    """Related program."""
    playlist = None
    """The playlist."""

    def __init__(self, controller, id=None, program=None, **kwargs):
        id = program.slug.replace("-", "_") if id is None else id
        self.program = program

        super().__init__(controller, id=id, **kwargs)
        self.path = os.path.join(self.station.path, f"{self.id}.m3u")

    def get_sound_queryset(self):
        """Get playlist's sounds queryset."""
        return self.program.sound_set.archive()

    def get_playlist(self):
        """Get playlist from db."""
        return self.get_sound_queryset().playlist()

    def write_playlist(self, playlist=[]):
        """Write playlist to file."""
        os.makedirs(os.path.dirname(self.path), exist_ok=True)
        with open(self.path, "w") as file:
            file.write("\n".join(playlist or []))

    def stream(self):
        """Return program's stream info if any (or None) as dict."""
        # used in templates
        # TODO: multiple streams
        stream = self.program.stream_set.all().first()
        if not stream or (not stream.begin and not stream.delay):
            return

        return {
            "begin": stream.begin.strftime("%Hh%M") if stream.begin else None,
            "end": stream.end.strftime("%Hh%M") if stream.end else None,
            "delay": to_seconds(stream.delay) if stream.delay else 0,
        }

    def sync(self):
        playlist = self.get_playlist()
        self.write_playlist(playlist)


class QueueSource(Source):
    queue = None
    """Source's queue (excluded on_air request)"""

    @property
    def requests(self):
        """Queue as requests metadata."""
        requests = [Request(self.controller, rid) for rid in self.queue]
        for request in requests:
            request.fetch()
        return requests

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def push(self, *paths):
        """Add the provided paths to source's play queue."""
        for path in paths:
            self.controller.send(f"{self.id}_queue.push {path}")

    def fetch(self):
        super().fetch()
        queue = self.controller.send(f"{self.id}_queue.queue").strip()
        if not queue:
            self.queue = []
            return

        self.queue = queue.split(" ")
