import os

from parallels.core import messages
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.logging import get_logger
from parallels.core.task_manager.manager import TaskManager, TaskOperations
from parallels.core.task_manager.task import Task
from parallels.core.utils.common import format_list
from parallels.core.utils.json_utils import read_json, write_json

logger = get_logger(__name__)


class CancelSubscriptions(CommonAction):
    """Cancel operations (migration, post-checks, etc) on specified subscriptions, request stop if running"""

    def get_description(self):
        """Get short description of action as string

        :rtype: str
        """
        return messages.ACTION_CANCEL_SUBSCRIPTIONS_DESCRIPTION

    def get_failure_message(self, global_context):
        """Get message for situation when action failed

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        return messages.ACTION_CANCEL_SUBSCRIPTIONS_FAILURE

    def get_logging_properties(self):
        """Get how action should be logged to migration tools end-user

        :rtype: parallels.core.actions.utils.logging_properties.LoggingProperties
        """
        return LoggingProperties(info_log=False)

    def run(self, global_context):
        """Run action

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        subscriptions = set(global_context.migration_list_data.subscriptions_mapping.keys())

        task_manager = TaskManager(global_context.session_files.get_file_path('tasks'))
        with task_manager.task_operations() as task_operations:
            assert isinstance(task_operations, TaskOperations)
            for task in task_operations.get_all_tasks():
                if task_operations.get_task_status(task) == Task.STATUS_RUNNING:
                    continue

                migration_list_file = os.path.join(task.task_dir, 'migration-list.json')
                if os.path.exists(migration_list_file):
                    remove_task = self._exclude_subscriptions_from_migration_list(
                        migration_list_file, subscriptions
                    )
                    if remove_task:
                        task_operations.set_task_status(task, Task.STATUS_CANCELLED)

            for subscription in subscriptions:
                global_context.subscriptions_status.remove_queued(subscription)
                global_context.subscriptions_status.set_stop(subscription)

            logger.finfo(messages.SUBSCRIPTIONS_CANCELLED, subscriptions=format_list(subscriptions))

    @staticmethod
    def _exclude_subscriptions_from_migration_list(migration_list_file, subscriptions):
        """Exclude subscriptions from migration list file.

        Return True if migration list becomes unnecessary and task can be completely removed from queue,
        False otherwise.

        :type migration_list_file: str | unicode
        :type subscriptions: set[str | unicode]
        :rtype: bool
        """
        data = read_json(migration_list_file)
        if 'subscriptions' not in data:
            return True

        for subscription in subscriptions:
            if subscription in data['subscriptions']:
                del data['subscriptions'][subscription]

        write_json(migration_list_file, data, pretty_print=True)

        return len(data['subscriptions']) == 0
