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.plesk.source.web import messages
from parallels.plesk.source.web.site_migration_list import SiteMigrationListReader
from parallels.plesk.source.web.tasks import Tasks
from parallels.plesk.source.web.utils.status_storage import StatusStorage
from parallels.plesk.source.web.utils.status_utils import set_status_for_all_migration_list_objects


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.web.global_context.WebGlobalMigrationContext
        """
        site_migration_list_filename = global_context.options.site_migration_list
        migration_list = SiteMigrationListReader().read(site_migration_list_filename)

        # Set all selected objects as queued - till we actually start the migration.
        source = global_context.conn.get_source()
        status_storage = StatusStorage(
            global_context.session_files.get_status_file(), source.config.host
        )
        set_status_for_all_migration_list_objects(
            migration_list, status_storage, StatusStorage.STATUS_QUEUED,
            Tasks.get_storage_status_type(migration_list.task)
        )
        # Split all objects in migration list into several tasks, one task per migrated object:
        # 1) Applications
        filter_applications = migration_list.filter_applications
        if filter_applications is not None:
            for application in filter_applications:
                self.add_task(global_context, {
                    'filter_applications': [
                        {
                            'type': application.application_type,
                            'source_path': application.source_path,
                            'target_path': application.target_path
                        },
                    ],
                    'task': Tasks.check_migration_list_task(migration_list.task)
                })
        # 2) Databases
        include_databases = migration_list.include_databases
        if include_databases is not None:
            for database in include_databases:
                self.add_task(global_context, {
                    'include_databases': [
                        {
                            'host': database.host,
                            'port': database.port,
                            'username': database.username,
                            'password': database.password,
                            'name': database.name
                        }
                    ]
                })

        # 3) Files (folders)
        include_files = migration_list.include_files
        if include_files is not None:
            for include_file in include_files:
                self.add_task(global_context, {
                    'include_files': [
                        {
                            'source_path': include_file.source_path,
                            'target_path': include_file.target_path
                        }
                    ]
                })

    @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: None 
        """
        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)
            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
            )
