import os

from parallels.core.logging import get_logger
from parallels.plesk.source.expand import messages
from parallels.core import MigrationError
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.utils.yaml_utils import write_yaml, read_yaml
from parallels.plesk.source.expand.expand_data.source import ExpandDataSource
from parallels.core.utils.common import format_list

logger = get_logger(__name__)


class FetchExpandData(CommonAction):
    def get_description(self):
        return messages.ACTION_FETCH_DATA_FROM_EXPAND_MAIN_SERVER_DESCRIPTION

    def get_failure_message(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        return messages.FAILED_TO_FETCH_DATA_FROM_EXPAND

    def run(self, global_context):
        """
        :type global_context: parallels.plesk.source.expand.global_context.ExpandGlobalMigrationContext
        """
        logger.info(messages.FETCH_PLESK_SERVERS_INFORMATION_FROM_EXPAND)

        expand_data_model_filename = global_context.session_files.get_path_to_expand_data_model_file()
        if not global_context.options.reload_source_data and os.path.exists(expand_data_model_filename):
            logger.info(messages.SKIP_LOADING_EXPAND_DATA_FILE)
            global_context.expand_data = read_yaml(expand_data_model_filename)
        else:
            data_source = ExpandDataSource(global_context.conn.expand_main_server)
            expand_data_model = data_source.get_model(
                global_context.conn.get_source_plesks(),
                global_context.conn.get_centralized_mail_servers()
            )
            self._check_source_data_complete(global_context, expand_data_model)
            global_context.expand_data = expand_data_model
            write_yaml(expand_data_model_filename, expand_data_model)

    @staticmethod
    def _check_source_data_complete(global_context, expand_objects):
        """Check that source data (model) is complete.
        At this moment only check that:
        - Expand Plesk servers in model include source Plesk servers selected in migrator configuration.
        - Expand centralized mail servers in model include centralized mail servers selected in migrator configuration.

        :type global_context: parallels.plesk.source.expand.global_context.ExpandGlobalMigrationContext
        """
        expand_plesk_server_plesk_ids = set([s.plesk_id for s in expand_objects.servers])
        config_plesk_server_plesk_ids = set(global_context.conn.get_source_plesks().keys())
        absent_plesk_server_plesk_ids = config_plesk_server_plesk_ids - expand_plesk_server_plesk_ids
        if len(absent_plesk_server_plesk_ids) > 0:
            raise MigrationError(
                messages.NO_EXPAND_PLESK_SERVERS_FOR_SOURCE_PLESK_SERVER % (
                    format_list(absent_plesk_server_plesk_ids),
                ) +
                messages.IP_ADDRESSES_DO_NOT_MATCH
            )

        expand_cmail_plesk_ids = set([c.plesk_id for c in expand_objects.centralized_mail_servers])
        config_cmail_plesk_ids = set(global_context.conn.get_centralized_mail_servers().keys())
        absent_cmail_plesk_ids = config_cmail_plesk_ids - expand_cmail_plesk_ids
        if len(absent_cmail_plesk_ids) > 0:
            raise MigrationError(
                messages.NO_EXPAND_CMAIL_SERVERS_FOR_SERVER_DESCRIBED_IN_CONFIG % (
                    format_list(absent_cmail_plesk_ids),
                ) +
                messages.IP_ADDRESSES_CMAIL_DO_NOT_MATCH
            )
