from collections import defaultdict

from parallels.core.migration_list.entities.subscription_source_info import SubscriptionSourceInfo
from parallels.core.registry import Registry
from parallels.core.utils.common import if_not_none, group_by_id, is_empty


class MigrationListSourceData(object):
    def __init__(self, dump_iterator):
        self._dump_iterator = dump_iterator

    def extract_subscriptions(
        self, subscriptions_mapping=None, subscription_filter=None
    ):
        """
        Returns list of SubscriptionSourceInfo
        """
        processed_subscriptions = set()
        subscriptions = []

        def add_subscription(reseller, client, plans, addon_plans, subscription):
            if (
                subscription.name not in processed_subscriptions and
                (subscription_filter is None or subscription.name in subscription_filter)
            ):
                if subscription_filter is None:
                    plan = if_not_none(subscription.plan_id, lambda subs_plan_id: plans.get(subs_plan_id))
                    addon_plans = {
                        addon_plans[plan_id]
                        for plan_id in subscription.addon_plan_ids
                        if plan_id in addon_plans
                    }
                else:
                    if subscriptions_mapping is not None:
                        # subscription is mapped to SubscriptionMappingInfo(plan, owner),
                        # and we want to display only the plan's name
                        plan = subscriptions_mapping[subscription.name].plan
                        addon_plans = subscriptions_mapping[subscription.name].addon_plans
                    else:
                        plan = if_not_none(subscription.plan_id, lambda subs_plan_id: plans[subs_plan_id])
                        addon_plans = {
                            addon_plans[plan_id]
                            for plan_id in subscription.addon_plan_ids
                            if plan_id in addon_plans
                        }
                subscriptions.append(SubscriptionSourceInfo(
                    name=subscription.name, name_canonical=subscription.name_canonical,
                    plan=plan, addon_plans=addon_plans,
                    reseller=reseller, customer=client
                ))
                processed_subscriptions.add(subscription.name)

        for _, backup in self._dump_iterator():
            admin_plans = dict((plan.id, plan.name) for plan in backup.get_plans())
            admin_addon_plans = {plan.id: plan.name for plan in backup.get_addon_plans()}
            for subscription in backup.iter_admin_subscriptions():
                admin_name = Registry.get_instance().get_context().target_panel_obj.get_default_admin_name()
                add_subscription(None, admin_name, admin_plans, admin_addon_plans, subscription)

            for client in backup.iter_clients():
                for subscription in client.subscriptions:
                    add_subscription(None, client.login, admin_plans, admin_addon_plans, subscription)

            for reseller in backup.iter_resellers():
                reseller_plans = dict((plan.id, plan.name) for plan in backup.iter_reseller_plans(reseller.login))
                reseller_addon_plans = {
                    plan.id: plan.name for plan in backup.iter_reseller_addon_plans(reseller.login)
                    }

                reseller_name = Registry.get_instance().get_context().target_panel_obj.get_default_reseller_name(
                    reseller
                )
                for subscription in reseller.subscriptions:
                    add_subscription(reseller.login, reseller_name, reseller_plans, reseller_addon_plans, subscription)

                for client in reseller.clients:
                    for subscription in client.subscriptions:
                        add_subscription(
                            reseller.login, client.login, reseller_plans, reseller_addon_plans, subscription
                        )

        return subscriptions

    def get_plans(self, target_service_templates, addon_plans=False):
        """
        Parameters:
        - addon_plans: if False, get regular (non-addon) plans, if True, get addon plans
        Return the following structure:
        plans[reseller_name][plan_name] = bool: whether this plan exists on target panel
        reseller_name is either a reseller login or None if reseller is admin
        """
        plans = defaultdict(dict)
        for _, backup in self._dump_iterator():
            if addon_plans:
                admin_plans = backup.get_addon_plans()
            else:
                admin_plans = backup.get_plans()

            for plan in admin_plans:
                plans[None][plan.name] = False
            for reseller in backup.iter_resellers():
                if addon_plans:
                    reseller_plans = backup.iter_reseller_addon_plans(reseller.login)
                else:
                    reseller_plans = backup.iter_reseller_plans(reseller.login)
                for plan in reseller_plans:
                    plans[reseller.login][plan.name] = False

        for reseller_login, template_names in target_service_templates.items():
            for template_name in template_names:
                plans[reseller_login][template_name] = True

        return plans

    def get_reseller_plans(self):
        """Get dictionary with keys - reseller logins, values - plans they are assigned to

        :rtype: dict[str | unicode, str | unicode]
        """
        reseller_plans = dict()
        for _, backup in self._dump_iterator():
            all_reseller_plans = group_by_id(
                backup.iter_admin_reseller_plans(),
                lambda p: p.id
            )

            for reseller in backup.iter_resellers():
                if reseller.login not in reseller_plans:
                    reseller_plans[reseller.login] = if_not_none(
                        all_reseller_plans.get(reseller.plan_id),
                        lambda plan: plan.name
                    )

        return reseller_plans

    def get_reseller_contacts(self):
        """Get dictionary with keys - reseller logins, values - their contact names

        :rtype: dict[str | unicode, str | unicode]
        """
        reseller_contacts = {}
        for _, backup in self._dump_iterator():
            for reseller in backup.iter_resellers():
                if reseller.login not in reseller_contacts:
                    if not is_empty(reseller.contact):
                        reseller_contacts[reseller.login] = reseller.contact
                    else:
                        reseller_contacts[reseller.login] = reseller.personal_info.get('name')
        return reseller_contacts

    def get_customer_contacts(self):
        customer_contacts = {}
        for _, backup in self._dump_iterator():
            for customer in backup.iter_all_clients():
                if customer.login not in customer_contacts:
                    if not is_empty(customer.contact):
                        customer_contacts[customer.login] = customer.contact
                    else:
                        customer_contacts[customer.login] = customer.personal_info.get('name')
        return customer_contacts

    def get_customer_owners(self):
        customer_owners = {}

        for _, backup in self._dump_iterator():
            for customer, owner in backup.iter_all_clients_with_owner():
                customer_owners[customer.login] = if_not_none(owner, lambda o: o.login)

        return customer_owners

    def get_source_subscriptions(self):
        mylist = []
        for _, backup in self._dump_iterator():
            for subscription in backup.iter_all_subscriptions():
                mylist.append(subscription.name)
        return mylist
