import os

import inspect

from django.conf import settings as d_settings


__all__ = ("Settings", "settings")


# code from django-fox
class BaseSettings:
    """Utility class used to load and save settings, can be used as model.

    Some members are excluded from being configuration:
    - Protected/private members;
    - On django model, "objects" and "Meta";
    - Class declaration and callables

    Example:

        ```
        class MySettings(Settings):
            a = 13
            b = 12

        my_settings = MySettings().load('MY_SETTINGS_KEY')
        print(my_settings.a, my_settings.get('b'))
        ```

    This will load values from django project settings.
    """

    def __init__(self, key, module=None):
        self.load(key, module)

    def load(self, key, module=None):
        """Load settings from module's item specified by its member name. When
        no module is provided, uses ``django.conf.settings``.

        :param str key: module member name.
        :param module: configuration object.
        :returns self
        """
        if module is None:
            module = d_settings
        settings = getattr(module, key, None)
        if settings:
            self.update(settings)
        return self

    def update(self, settings):
        """Update self's values from provided settings. ``settings`` can be an
        iterable of ``(key, value)``.

        :param dict|Settings|iterable settings: value to update from.
        """
        if isinstance(settings, (dict, Settings)):
            settings = settings.items()
        for key, value in settings:
            if self.is_config_item(key, value):
                setattr(self, key, value)

    def get(self, key, default=None):
        """Return settings' value for provided key."""
        return getattr(self, key, default)

    def items(self):
        """Iterate over items members, as tupple of ``key, value``."""
        for key in dir(self):
            value = getattr(self, key)
            if self.is_config_item(key, value):
                yield key, value

    def is_config_item(self, key, value):
        """Return True if key/value item is a configuration setting."""
        if key.startswith("_") or callable(value) or inspect.isclass(value):
            return False
        return True


class Settings(BaseSettings):
    # --- Global & misc
    DEFAULT_USER_GROUPS = {
        "radio hosts": (
            # TODO include content_type in order to avoid clash with potential
            #      extra applications
            # aircox
            "view_program",
            "view_episode",
            "change_diffusion",
            "add_comment",
            "change_comment",
            "delete_comment",
            "add_article",
            "change_article",
            "delete_article",
            "change_sound",
            "add_track",
            "change_track",
            "delete_track",
            # taggit
            "add_tag",
            "change_tag",
            "delete_tag",
            # filer
            "add_folder",
            "change_folder",
            "delete_folder",
            "can_use_directory_listing",
            "add_image",
            "change_image",
            "delete_image",
        ),
    }
    """Groups to assign to users at their creation, along with the permissions
    to add to each group."""
    PROGRAMS_DIR = "programs"
    """Directory for the programs data."""

    @property
    def PROGRAMS_DIR_ABS(self):
        return os.path.join(d_settings.MEDIA_ROOT, self.PROGRAMS_DIR)

    # --- Programs & episodes
    EPISODE_TITLE = "{program.title} - {date}"
    """Default title for episodes."""
    EPISODE_TITLE_DATE_FORMAT = "%-d %B %Y"
    """Date format in episode title (python's strftime)"""

    # --- Logs & archives
    LOGS_ARCHIVES_DIR = "logs/archives"
    """Directory where to save logs' archives."""

    @property
    def LOGS_ARCHIVES_DIR_ABS(self):
        return os.path.join(d_settings.PROJECT_ROOT, self.LOGS_ARCHIVES_DIR)

    LOGS_ARCHIVES_AGE = 60
    """In days, minimal age of a log before it is archived."""

    # --- Sounds
    SOUND_ARCHIVES_SUBDIR = "archives"
    """Sub directory used for the complete episode sounds."""
    SOUND_EXCERPTS_SUBDIR = "excerpts"
    """Sub directory used for the excerpts of the episode."""
    SOUND_QUALITY = {
        "attribute": "RMS lev dB",
        "range": (-18.0, -8.0),
        "sample_length": 120,
    }
    """Quality attributes passed to sound_quality_check from sounds_monitor
    (Soxi parameters)."""
    SOUND_FILE_EXT = (".ogg", ".flac", ".wav", ".mp3", ".opus")
    """Extension of sound files."""
    SOUND_KEEP_DELETED = False
    """Tag sounds as deleted instead of deleting them when file has been
    removed from filesystem (sound monitoring)."""

    # --- Streamer & Controllers
    CONTROLLERS_WORKING_DIR = "/tmp/aircox"
    """Controllers working directory."""

    # --- Playlist import from CSV
    IMPORT_PLAYLIST_CSV_COLS = (
        "artist",
        "title",
        "minutes",
        "seconds",
        "tags",
        "info",
    )
    """Columns for CSV file."""
    IMPORT_PLAYLIST_CSV_DELIMITER = ";"
    """Column delimiter of csv text files."""
    IMPORT_PLAYLIST_CSV_TEXT_QUOTE = '"'
    """Text delimiter of csv text files."""


settings = Settings("AIRCOX")
