from parallels.core.utils.common import cached, group_by_id
from parallels.plesk.source.plesk.shallow_dump.model.base.constants import PLESK_ADMIN_ID
from parallels.plesk.source.plesk.shallow_dump.model.base.template import Template


class ShallowDumpModel(object):
    """Shallow dump object - information about clients, domains, resellers, etc necessary to create migration list

    This class is abstract - see different implementations for different source panels.
    """

    @property
    def clients(self):
        """Get all clients of the Plesk

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.client.Client]
        """
        raise NotImplementedError()

    @property
    @cached
    def admin_clients(self):
        """Clients owned directly by administrator

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.client.Client]
        """
        return [client for client in self.clients if client.owner_id in self.admin_ids]

    def get_reseller_clients(self, reseller_id):
        """Get clients owned by specified reseller

        :type reseller_id: str | unicode
        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.client.Client]
        """
        return [client for client in self.clients if client.owner_id == reseller_id]

    @property
    @cached
    def resellers(self):
        """Get all resellers of the Plesk

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.reseller.Reseller]
        """
        raise NotImplementedError()

    @property
    @cached
    def domains(self):
        """Get all domains of the Plesk

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.domain.Domain]
        """
        raise NotImplementedError()

    @property
    def admin_domains(self):
        """Domains owned directly by administrator

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.domain.Domain]
        """
        return [domain for domain in self.domains if domain.owner_id in self.admin_ids]

    def get_client_domains(self, client_id):
        """Get domains owned by specified client

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.domain.Domain]
        """
        return [domain for domain in self.domains if domain.owner_id == client_id]

    def get_reseller_domains(self, reseller_id):
        """Get domains owned by specified reseller

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.domain.Domain]
        """
        return [domain for domain in self.domains if domain.owner_id == reseller_id]

    @property
    @cached
    def templates(self):
        """Get all templates (domain and reseller, addon and regular, owned by admin and resellers)

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.template.Template]
        """
        raise NotImplementedError()

    @property
    @cached
    def templates_by_id(self):
        """Get templates (reseller and client) grouped by ID

        :rtype: dict[str | unicode, parallels.plesk.source.plesk.shallow_dump.model.base.template.Template]
        """
        return group_by_id(self.templates, lambda template: template.template_id)

    @property
    def admin_domain_templates(self):
        """Domain templates owned directly by administrator

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.template.Template]
        """
        return [
            template for template in self.templates
            if (
                template.owner_id in self.admin_ids
                and template.template_type in (Template.TEMPLATE_TYPE_DOMAIN, Template.TEMPLATE_TYPE_DOMAIN_ADDON)
            )
        ]

    @property
    def admin_reseller_templates(self):
        """Reseller templates owned directly by administrator

        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.template.Template]
        """
        return [
            template for template in self.templates
            if template.owner_id in self.admin_ids and template.template_type == Template.TEMPLATE_TYPE_RESELLER
        ]

    def get_reseller_domain_templates(self, reseller_id):
        """Get domain templates owned by specified reseller

        :type reseller_id: str | unicode
        :rtype: list[parallels.plesk.source.plesk.shallow_dump.model.base.template.Template]
        """
        return [
            template for template in self.templates
            if (
                template.owner_id == reseller_id
                and template.template_type in (Template.TEMPLATE_TYPE_DOMAIN, Template.TEMPLATE_TYPE_DOMAIN_ADDON)
            )
        ]

    @property
    def subscription_id_to_plan_ids(self):
        """Get subscription ID to plan IDs mapping

        For example: {1: [5, 6], 3: [2]}, where subscription with ID 1 is assigned to 2 plans - one with ID 5, another
        one with ID 6, and subscription with ID 3 is assigned to plan with ID 2.

        :rtype: dict[str | unicode, list[str | unicode]]
        """
        raise NotImplementedError()

    @property
    def admin_ids(self):
        return {PLESK_ADMIN_ID}