from parallels.core import safe_format
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.application.prestashop import PrestashopModel
from parallels.core.application.utils import replace_line_bounds
from parallels.core.connections.plesk_server import PleskServer
from parallels.core.logging import get_logger
from parallels.core.reports.model.issue import Issue
from parallels.core.runners.base import BaseRunner
from parallels.plesk.source.web import messages
from parallels.plesk.source.web.actions.base.application import ApplicationAction

logger = get_logger(__name__)


class DisablePrestashopCache(ApplicationAction):
    """Disable PrestaShop cache (APC, memcached, etc), as it usually does not work after migration to Plesk.
    
    ATTENTION: This action very arguable: customers, who configured APC/memcached 
    on the target server before migration will loose performance tuning on their PrestaShop and will be 
    very surprised/disappointed.
    
    Better solution includes checking if we have APC/memcached on the target server, and disabling caching
    only if there is no required caching module. 
    The best solution suggests customer to choose between disabling cache and automatic installation 
    of required caching module.
    """

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

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

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

        If action is critical and it failed, migration tool completely stops.
        Otherwise it proceeds to the next steps of migrations.

        :rtype: bool
        """
        return False

    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_DISABLE_PRESTASHOP_CACHE_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 get_failure_message_for_application(self, global_context, application):
        """Get message for situation when action failed for specific application

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: str | unicode | None
        """
        return safe_format(
            messages.ACTION_DISABLE_PRESTASHOP_CACHE_FAILURE_FOR_APP,
            application_type=application.application_model.name,
            path=application.target_path
        )

    def get_failure_severity_for_application(self):
        """Get issue severity for application in case if that action failed

        :rtype: str | unicode
        """
        return Issue.SEVERITY_WARNING

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

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: None
        """
        return application.application_model.name == PrestashopModel().name

    def run_for_application(self, global_context, application):
        """Run action for single migrated application

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: list[parallels.core.reports.model.issue.Issue] | None
        """
        issues = []

        target_server = global_context.conn.target.plesk_server
        assert isinstance(target_server, PleskServer)

        config_path = target_server.join_path(application.target_path, 'app', 'config', 'parameters.php')

        with target_server.runner() as runner:
            assert isinstance(runner, BaseRunner)

            if not runner.file_exists(config_path):
                return issues

            config_contents = runner.get_file_contents(config_path)

            # Example of config file line:
            #     'ps_cache_enable' => true,
            replace_results = replace_line_bounds(
                config_contents,
                condition_strs=['ps_cache_enable'],
                start_strs=["""['"]ps_cache_enable['"]\s*=>\s*"""],
                end_str="""\s*,""",
                replace_mapping={'true': 'false'},
                regex=True
            )

            if replace_results.has_changes:
                runner.upload_file_content(config_path, replace_results.new_contents)
                for changed_line in replace_results.changed_lines:
                    issues.append(
                        Issue(
                            'prestashop_disable_cache', Issue.SEVERITY_INFO,
                            safe_format(
                                messages.APPLICATION_REPLACE_FILE_CONTENT,
                                application_instance_description=application.description(),
                                reason=messages.PRESTASHOP_DISABLE_CACHING_REASON,
                                file=config_path,
                                line_number=changed_line.line_number,
                                before_fix=changed_line.old_contents.strip(),
                                after_fix=changed_line.new_contents.strip()
                            ),
                        )
                    )

        return issues
