import os

from parallels.core import safe_format
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.logging import get_logger
from parallels.core.utils.stop_mark import check_stop_mark
from parallels.plesk.source.web import messages
from parallels.plesk.source.web.actions.base.folder import FolderAction

logger = get_logger(__name__)


class AdjustSiteNameChange(FolderAction):
    """Adjust configuration files if site name was changed.

    That is a quick-and-dirty fix for migration from PfW to PfW, when site name was changed:
    web.config and .user.ini files contain references to old site name and to old file paths.
    These files makes applications (e.g. WordPress) broken on the target server.
    In that action we replace old site name with new site name in these files.
    """

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

        :rtype: str | unicode
        """
        return messages.ACTION_ADJUST_SITE_NAME_CHANGE_DESCRIPTION

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

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode
        """
        return messages.ACTION_ADJUST_SITE_NAME_CHANGE_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(compound=False)

    def is_critical(self):
        """If action is critical or not

        If action is critical and it failed for a subscription, migration tool
        won't run the next operations for the subscription.

        :rtype: bool
        """
        return False

    def filter_action(self, global_context):
        """Check whether we should run this action or not. By default True - action should be executed.

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :rtype: bool
        """
        return (
            global_context.conn.get_source().config.host !=
            global_context.conn.get_source().config.target_domain
        )

    def get_failure_message_for_folder(self, global_context, folder):
        """Get message for situation when action failed for specific folder

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type folder: parallels.plesk.source.web.migrated_folder.MigratedFolder
        :rtype: str | unicode | None
        """
        return safe_format(
            messages.ACTION_ADJUST_SITE_NAME_CHANGE_FAILURE_FOR_FOLDER,
            target_folder=folder.target_path
        )

    def run_for_folder(self, global_context, folder):
        """Run action for single migrated database user

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type folder: parallels.plesk.source.web.migrated_folder.MigratedFolder
        :rtype: list[parallels.core.reports.model.issue.Issue] | None
        """
        source_domain_name = global_context.conn.get_source().config.host
        target_domain_name = global_context.conn.get_source().config.target_domain

        with folder.target_server.runner() as runner:
            filename_iterator = runner.iter_files_list_nested(folder.target_path)

            check_stop_mark(global_context.stop_mark)

            for filename in filename_iterator:
                check_stop_mark(global_context.stop_mark)

                basename = os.path.basename(filename)

                # Fix only these 2 files
                if basename not in {'web.config', '.user.ini'}:
                    continue

                if runner.get_file_size(filename) > 1024 * 1024:
                    # Skip large files that are > 1MB, to avoid high memory usage.
                    # Code and configuration files should be always small.
                    return

                with open(filename) as fp:
                    contents = fp.read()

                fixed_contents = contents.replace(source_domain_name, target_domain_name)

                if fixed_contents != contents:
                    logger.fdebug(
                        messages.ADJUSTED_SITE_NAME,
                        filename=filename, source_domain_name=source_domain_name, target_domain_name=target_domain_name
                    )
                    with open(filename, 'w') as fp:
                        fp.write(fixed_contents)
