"""Module for managing feature flags"""
from __future__ import annotations

import dataclasses
import json
import typing
from urllib import parse

import anaconda_anon_usage.tokens as anon_tokens
from qtpy.QtCore import QObject, Signal, QTimer

from anaconda_navigator.config import CONF, FEATURE_FLAGS_JSON_PATH
from anaconda_navigator.utils import download_manager
from anaconda_navigator.utils import singletons


def prepare_context() -> bytes:
    """Get context attributes."""
    return json.dumps({
        'key': anon_tokens.client_token() or 'default'
    }).encode()


@dataclasses.dataclass(eq=False)
class FeatureFlags:
    """Feature flags store."""
    survey_url: str = ''
    known_channels: tuple[str, ...] = (
        'defaults', 'anaconda', 'astropy', 'beeware', 'binstar', 'biobuilds', 'bioconda', 'conda-forge', 'esri', 'free',
        'intel', 'main', 'menpo', 'msys2', 'omnia', 'pro', 'pytorch', 'qiime2', 'r', 'rapidsai', 'rapidsai-nightly',
        'rdkit', 'mgoetze', 'conda-test', 'conda-canary', 'anaconda-client-test', 'navigator-test'
    )


class FeatureFlagsManager(QObject):
    """Class for managing the loading and caching of feature flags."""

    sig_flags_loaded = Signal()

    def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None:
        """Initialize new :class:`~FeatureFlagsManager` instance."""
        super().__init__(*args, **kwargs)
        self.__timer: QTimer = QTimer()
        self.__loaded: bool = False
        self.__base_url = CONF.get('internal', 'launchdarkly_proxy_base_url')

    def __set_loaded(self, value: bool = True) -> None:
        self.__loaded = value
        self.sig_flags_loaded.emit()

    def load(self) -> None:
        """Load feature flags from a remote source to the cache file."""
        if not self.__base_url:
            self.__load_cached()
            return

        self.__timer.singleShot(5_000, self.__load_cached)
        download: download_manager.Download = download_manager.Download(
            parse.urljoin(self.__base_url, 'v1/feature-flags')
        ).into(FEATURE_FLAGS_JSON_PATH).attach('POST', prepare_context())
        download.sig_succeeded.connect(self.__load_cached)
        download_manager.Manager().execute(download)

    def __load_cached(self) -> None:
        """Load feature flags from the cache file."""
        self.__timer.stop()

        if self.__loaded:
            return

        try:
            stream: typing.TextIO
            with open(FEATURE_FLAGS_JSON_PATH, 'rt', encoding='utf-8') as stream:
                cached_flags = json.load(stream)
                for flag_key, value in cached_flags.items():
                    if hasattr(FEATURE_FLAGS, flag_key):
                        setattr(FEATURE_FLAGS, flag_key, value)
        except (OSError, TypeError, ValueError):
            pass
        finally:
            self.__set_loaded()


FEATURE_FLAGS: FeatureFlags = FeatureFlags()
FEATURE_FLAGS_MANAGER: typing.Final[
    singletons.Singleton[FeatureFlagsManager]] = singletons.SingleInstanceOf(FeatureFlagsManager)
