import os
import shutil

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.migration_list.reader.json_reader import MigrationListReaderJSON
from parallels.core.task_manager.manager import TaskManager, TaskOperations
from parallels.core.utils.common import unused, open_no_inherit, read_file_contents
from parallels.core.utils.json_utils import read_json
from parallels.core.utils.migration_progress import SubscriptionMigrationStatus
from parallels.core.utils.migrator_utils import get_optional_option_value
from parallels.core.utils.subscription_operations import command_name_to_operation

logger = get_logger(__name__)


class AddTaskAction(CommonAction):
    """Add task to a queue

    Task consists of 2 parts:
    1) Command to be executed, for example 'transfer-accounts' or 'copy-web-content'.
    Command is stored as JSON file, which contains command to be executed and list of additional arguments.
    2) List of subscriptions on which the command should be executed.
    Format of the file is JSON migration list.

    This command adds a new task to the queue. Required arguments are file with command description (JSON) and
    migration list file (JSON).
    """
    def get_description(self):
        """Get short description of action as string

        :rtype: str
        """
        return messages.ACTION_ADD_TASK_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_ADD_TASK_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
        """
        task_manager = TaskManager(global_context.session_files.get_file_path('tasks'))

        with task_manager.task_operations() as task_operations:
            assert isinstance(task_operations, TaskOperations)

            task_id = get_optional_option_value(global_context.options, 'task_id', None)
            task = task_operations.create_task(task_id)

            task_command_file = os.path.join(task.task_dir, 'command.json')
            shutil.copyfile(global_context.options.command_file, task_command_file)

            if global_context.options.migration_list_file is not None:
                task_migration_list_file = os.path.join(task.task_dir, 'migration-list.json')
                shutil.copyfile(global_context.options.migration_list_file, task_migration_list_file)

                self._mark_subscriptions_as_queued(global_context)
            else:
                task_migration_list_file = None

            task_operations.schedule_task(task)

            if global_context.options.migration_list_file is not None:
                logger.finfo(
                    messages.SCHEDULED_TASK_WITH_MIGRATION_LIST,
                    task_id=task.task_id, task_dir=task.task_dir,
                    migration_list_file=task_migration_list_file,
                    command=read_file_contents(task_command_file)
                )
            else:
                logger.finfo(
                    messages.SCHEDULED_TASK_WITHOUT_MIGRATION_LIST,
                    task_id=task.task_id, task_dir=task.task_dir,
                    migration_list_file=task_migration_list_file,
                    command=read_file_contents(task_command_file)
                )

    @staticmethod
    def _mark_subscriptions_as_queued(global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        command_info = read_json(global_context.options.command_file)
        command_name = command_info['command']
        migration_list_reader = MigrationListReaderJSON(
            global_context.migrator.get_migration_list_source_data()
        )
        with open_no_inherit(global_context.options.migration_list_file, 'r') as fp:
            migration_list_data, errors = migration_list_reader.read(fp, subscriptions_only=True)
            # migration list errors are simply ignored here,
            # anyway you will see them once the task is executed
            unused(errors)
            for subscription_name in migration_list_data.subscriptions_mapping.keys():
                operation = command_name_to_operation(command_name)
                if operation is not None:
                    global_context.subscriptions_status.set_operation_status(
                        subscription_name, operation, SubscriptionMigrationStatus.ON_HOLD
                    )
                global_context.subscriptions_status.set_queued(subscription_name)
                global_context.subscriptions_status.remove_stop(subscription_name)
