from __future__ import annotations

import os
import sys
from pathlib import Path

from clarabot_nano.utility.path.common import normalize_validate_resolve_absolute_path


class AbstractDirectories(object):
    """
    Provide platform specific safe defaults to different storage related queries.
    """

    _INSTANCE = None

    @staticmethod
    def instance() -> AbstractDirectories:
        return AbstractDirectories._INSTANCE

    @classmethod
    def reset_instance(cls, *args, **kwargs):
        AbstractDirectories._INSTANCE = cls(*args, **kwargs)

    def get_user_app_data_dir(self, app_name, *names) -> Path:
        """
        Default directory where application data shall be stored.
        """
        raise NotImplementedError

    def get_user_app_config_dir(self, app_name, *names) -> Path:
        """
        Default directory where application configuration shall be stored. These are usually plain text or easily
        editable by the user to customize the application as they see fit.
        """
        raise NotImplementedError


if sys.platform.startswith("win"):

    class WindowsDirectories(AbstractDirectories):
        """
        User directories:
        Unlike other common platforms, an application's "data" and "config" files are not separated by convention.
        To make things semantically similar we add categorizing subdirectories as a workaround.
        """

        def __init__(self, local=True):
            self._data = normalize_validate_resolve_absolute_path(os.environ["LOCALAPPDATA" if local else "APPDATA"])

        def get_user_app_data_dir(self, app_name, *names) -> Path:
            return Path(self._data, app_name, "data", *names)

        def get_user_app_config_dir(self, app_name, *names) -> Path:
            return Path(self._data, app_name, "config", *names)

    Directories = WindowsDirectories

elif sys.platform.startswith("darwin"):

    class MacOSDirectories(AbstractDirectories):
        def __init__(self, **kwargs):
            self._home = normalize_validate_resolve_absolute_path(os.environ["HOME"])

        def get_user_app_data_dir(self, app_name, *names) -> Path:
            return Path(self._home, "Library", "Application Support", app_name, *names)

        def get_user_app_config_dir(self, app_name, *names) -> Path:
            return Path(self._home, "Library", "Preferences", app_name, *names)

    Directories = MacOSDirectories

else:

    class UnixDirectories(AbstractDirectories):
        """
        User directories:
        Try to use XDG variables, then fallback to unix convention.
        """

        def __init__(self, **kwargs):
            self._config = normalize_validate_resolve_absolute_path(
                os.environ.get("XDG_CONFIG_HOME", os.path.join(os.environ["HOME"], ".config"))
            )
            self._data = normalize_validate_resolve_absolute_path(
                os.environ.get("XDG_DATA_HOME", os.path.join(os.environ["HOME"], ".local", "share"))
            )

        def get_user_app_data_dir(self, app_name, *names) -> Path:
            return Path(self._data, app_name, *names)

        def get_user_app_config_dir(self, app_name, *names) -> Path:
            return Path(self._config, app_name, *names)

    Directories = UnixDirectories


# Create default instance to use.
Directories.reset_instance()
