# coding=utf-8

# =============================================================================
# IMPORTS
# =============================================================================

import abc

from .Elements import Elements

# from .Subject import Subject

# =============================================================================
# NOTES
# =============================================================================

# https://front.arcopole.fr/orion_fed_105/orion/admin/tree/rightmanagement/groups/__children

# =============================================================================
# CLASS
# =============================================================================


class Subjects(Elements):
    """
    Class allowing to get access to the defined groups

    """

    def __init__(self, subject_type, id_key, title_key):
        super().__init__()

        self.subject_type = subject_type
        self.title_key = title_key
        self.id_key = id_key

    @abc.abstractmethod
    def _get_system_subject_id(self):
        """Return list of subject id"""
        raise NotImplementedError(
            "class must define _get_system_subject_id() to use this base class"
        )

    def _update(self):
        """Make sure that list of elements is up to date with DB state.
        Name is the key to get a particular group
        """
        self._elements = {}
        next_start = 0

        # Get portal self description
        self_portal = self.request.get_in_python(self.url_manager.self_url())
        org_id = self_portal["id"]

        while next_start != -1:
            next_start = self._search_subjects(org_id, next_start)

    def _search_subjects(self, org_id, next_start):
        """Look for a particular group in the list using its id

        :param org_id: org id of portal
        :param start: start value to request
        :return: next_start value. if value is -1 there is no more data
        """
        params = {"f": "json"}
        params[
            "q"
        ] = "(orgid:{org_id} -username:esri_livingatlas -username:esri_boundaries -username:esri_demographics -username:esri_nav -owner:esri_livingatlas -owner:esri_boundaries -owner:esri_demographics -owner:esri_nav)".format(
            org_id=org_id
        )
        params["num"] = 100
        params["start"] = next_start

        subject_structs = self.request.get_in_python(
            self.url_manager.subject_list_url(self.subject_type), params
        )

        for subject_struct in subject_structs["results"]:
            subject_id = subject_struct[self.id_key]
            subject_title = subject_struct.get(self.title_key) or subject_struct.get(
                self.id_key
            )

            if self._elements.get(subject_title):
                subject_title += "({id})".format(id=subject_id)

            self._elements[subject_title] = self._create_subject_instance(
                subject_title, subject_id, None
            )
        return subject_structs["nextStart"]

    @abc.abstractmethod
    def _create_subject_instance(self, subject_title, subject_id, profile_id):
        """Create instance of the specific subject"""
        raise NotImplementedError(
            "class must define _create_subject_instance() to use this base class"
        )

    def get_with_id(self, subject_id):
        """Look for a particular group in the list using its id

        :param group_id: id of the group to look for
        :return: the required group or None if nothing found
        """
        self._update()
        subject_id = subject_id.strip()
        for key, subject in self._elements.items():
            if subject.id == subject_id:
                return subject
        return None

    def all(self):
        """
        :return: the list of elements' values
        """
        # TODO convert to list ?
        self._update()
        return sorted(self._elements.values(), key=lambda group: group.title.lower())
