from parallels.core.actions.base.common_action import CommonAction
from parallels.core.utils.common import is_empty_iterator, if_not_none


class CustomerAction(CommonAction):
    """Base class for actions performed on customers
    """

    def filter_action(self, global_context):
        return not is_empty_iterator(global_context.target_model.iter_all_customers())

    def run(self, global_context):
        target_model = global_context.target_model

        for client in target_model.clients.values():
            if client.login is None:
                # skip fake clients (owners of admin subscriptions in model)
                continue

            with global_context.safe.try_client(
                None,
                client.login,
                self._get_customer_failure_message(global_context, client)
            ):
                self._run_customer(global_context, client, None)

        for reseller in target_model.resellers.values():
            for client in reseller.clients:
                if client.login == reseller.login:
                    # skip fake clients (owners of reseller subscriptions in model)
                    continue
                reseller_username = if_not_none(reseller, lambda r: r.login)
                with global_context.safe.try_client(
                    reseller_username,
                    client.login,
                    self._get_customer_failure_message(global_context, client)
                ):
                    self._run_customer(global_context, client, reseller_username)

    def _get_customer_failure_message(self, global_context, customer):
        """Retrieve error message if operation on specific customer failed

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type customer: parallels.core.target_data_model.Client
        """
        raise NotImplementedError()

    def _run_customer(self, global_context, customer, reseller_username=None):
        """Run action on specific customer

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type customer: parallels.core.target_data_model.Client
        :type reseller_username: str | None
        """
        raise NotImplementedError()
