import json
import os

from parallels.core import get_logger
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.task_manager.manager import TaskManager, TaskOperations
from parallels.core.utils.common import read_file_contents
from parallels.core.utils.json_utils import write_json
from parallels.core.utils.migrator_utils import get_option_value_safe
from parallels.plesk.source.mail.mail_migration_list import MailMigrationListReader
from parallels.plesk.source.mail.status_storage import StatusStorage
from parallels.plesk.source.mail import messages

logger = get_logger(__name__)


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

        :rtype: str
        """
        return messages.ACTION_ADD_TASKS_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_TASKS_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.plesk.source.mail.global_context.MailGlobalMigrationContext
        """
        mail_migration_list_filename = global_context.options.mail_migration_list
        migration_list = MailMigrationListReader().read(mail_migration_list_filename)

        status_storage = StatusStorage(
            global_context.session_files.get_global_status_file().path,
            global_context.session_files.get_global_status_file_lock().path
        )
        for mail_address_pair in migration_list.mail_address_pairs:
            if get_option_value_safe(global_context.options, 'async_status_report', False):
                status_storage.set_reporting_mode(StatusStorage.REPORTING_MODE_ASYNC)
                status_storage.set_global_restored_message_num(
                    mail_address_pair.source_email, mail_address_pair.target_mailname, None
                )
                status_storage.set_global_status(
                    mail_address_pair.source_email, mail_address_pair.target_mailname, StatusStorage.STATUS_QUEUED
                )

        last_task = None
        for mail_address_pair in migration_list.mail_address_pairs:
            last_task = self.add_task(
                global_context, dict(mail_address_pairs=[mail_address_pair.as_encrypted_dictionary()])
            )

        print(json.dumps(dict(
            task_id=last_task.task_id
        )))

    @staticmethod
    def add_task(global_context, migration_list_data):
        """Add migration task with specified site migration list contents

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type migration_list_data: dict
        :rtype: parallels.core.task_manager.task.Task
        """
        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 = task_operations.create_task()
            task_migration_list_file = os.path.join(task.task_dir, 'migration-list.json')
            write_json(task_migration_list_file, migration_list_data, pretty_print=True)
            if get_option_value_safe(global_context.options, 'async_status_report', False):
                with open(os.path.join(task.task_dir, 'async_status_report'), 'w'):
                    pass
            task_operations.schedule_task(task)
            logger.finfo(
                messages.SCHEDULED_TASK,
                task_id=task.task_id, migration_list=read_file_contents(task_migration_list_file),
                task_dir=task.task_dir
            )
            return task
