import os

from django.db import models
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _

from aircox.conf import settings

from .page import Page
from .program import ProgramChildQuerySet
from .sound import Sound

__all__ = ("Episode",)


class EpisodeQuerySet(ProgramChildQuerySet):
    def with_podcasts(self):
        return self.filter(episodesound__sound__is_public=True).distinct()


class Episode(Page):
    objects = EpisodeQuerySet.as_manager()
    detail_url_name = "episode-detail"
    list_url_name = "episode-list"
    template_prefix = "episode"

    @property
    def program(self):
        return self.parent_subclass

    @program.setter
    def program(self, value):
        self.parent = value

    @cached_property
    def podcasts(self):
        """Return serialized data about podcasts."""
        query = self.episodesound_set.all().public().order_by("-broadcast", "position")
        return self._to_podcasts(query)

    @cached_property
    def sounds(self):
        """Return serialized data about all related sounds."""
        query = self.episodesound_set.all().order_by("-broadcast", "position")
        return self._to_podcasts(query)

    def _to_podcasts(self, query):
        from ..serializers import EpisodeSoundSerializer as serializer_class

        query = query.select_related("sound")
        podcasts = [serializer_class(s).data for s in query]
        for index, podcast in enumerate(podcasts):
            podcasts[index]["page_url"] = self.get_absolute_url()
            podcasts[index]["page_title"] = self.title
        return podcasts

    class Meta:
        verbose_name = _("Episode")
        verbose_name_plural = _("Episodes")

    def get_absolute_url(self):
        if not self.is_published:
            return self.program.get_absolute_url()
        return super().get_absolute_url()

    def save(self, *args, **kwargs):
        if self.parent is None:
            raise ValueError("missing parent program")
        super().save(*args, **kwargs)

    @classmethod
    def get_default_title(cls, page, date):
        return settings.EPISODE_TITLE.format(
            program=page,
            date=date.strftime(settings.EPISODE_TITLE_DATE_FORMAT),
        )

    @classmethod
    def get_init_kwargs_from(cls, page, date=None, title=None, **kwargs):
        """Get default Episode's title."""
        title = (
            settings.EPISODE_TITLE.format(
                program=page,
                date=date.strftime(settings.EPISODE_TITLE_DATE_FORMAT),
            )
            if title is None
            else title
        )
        return super().get_init_kwargs_from(page, title=title, program=page, **kwargs)


class EpisodeSoundQuerySet(models.QuerySet):
    def episode(self, episode):
        if isinstance(episode, int):
            return self.filter(episode_id=episode)
        return self.filter(episode=episode)

    def available(self):
        return self.filter(sound__is_removed=False)

    def public(self):
        return self.filter(sound__is_public=True)

    def broadcast(self):
        return self.available().filter(broadcast=True)

    def playlist(self, order="position"):
        if order:
            self = self.order_by(order)
        return [
            os.path.join(settings.MEDIA_ROOT, file)
            for file in self.filter(file__isnull=False, is_removed=False).Values_list("file", flat=True)
        ]


class EpisodeSound(models.Model):
    """Element of an episode playlist."""

    episode = models.ForeignKey(Episode, on_delete=models.CASCADE)
    sound = models.ForeignKey(Sound, on_delete=models.CASCADE)
    position = models.PositiveSmallIntegerField(
        _("order"),
        default=0,
        help_text=_("position in the playlist"),
    )
    broadcast = models.BooleanField(
        _("Broadcast"),
        blank=None,
        help_text=_("The sound is broadcasted on air"),
    )

    objects = EpisodeSoundQuerySet.as_manager()

    class Meta:
        verbose_name = _("Episode Sound")
        verbose_name_plural = _("Episode Sounds")

    def save(self, *args, **kwargs):
        if self.broadcast is None:
            self.broadcast = self.sound.broadcast
        super().save(*args, **kwargs)
