from parallels.core.dump.data_model import WebSetting
from parallels.core.hosting_repository.virtual_hosting_settings import WebServerDirectivesEntity
from parallels.core.logging import get_logger
from parallels.core.utils.common import is_empty
from parallels.plesk.source.plesk import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction

logger = get_logger(__name__)


class RestoreAdditionalWebServerDirectives(SubscriptionAction):
    """Restore additional web server directives for Apache and nginx
    
    The directives have to be restore separately of other hosting settings because of the following:
    - Restoration of other hosting settings is done with the help of PMM
    - PMM uses optimization so configuration files are written only once at the end of restoration:
      during restoration they are stored in Plesk database only
    - So, restoration command is executed with additional environment variable like: 
      PLESK_RESTORE_EXCLUDE_BACKEND=apache-config,apache_control_adapter,...
    - Additional web server directives are stored only in the files, not in Plesk database
    - So, when backend execution is skipped, we completely loose the directives.
    
    So, here we execute the same command as PMM does, but without PLESK_RESTORE_EXCLUDE_BACKEND, so directives
    are immediately propagated to files.
    """

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

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

    def get_failure_message(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        return messages.ACTION_RESTORE_ADDITIONAL_WEB_SERVER_DIRECTIVES_FAILURE

    def is_critical(self):
        """Get message for situation when action failed

        :rtype: str | unicode
        """
        return False

    def filter_subscription(self, global_context, subscription):
        """Check if we should run this action on given subscription or not

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: bool
        """
        if global_context.conn.target.plesk_server.get_plesk_version() >= (18, 0, 27):
            """Have to filter out all subscriptions
            because command backup_restore_helper --restore-subscription
            is excluded from Plesk
            """
            return False

        if subscription.web_target_server is None:
            return False

        if subscription.web_target_server.is_windows():
            return False

        web_server_directives_settings = [
            WebSetting.SETTING_APACHE_ADDITIONAL_SETTINGS,
            WebSetting.SETTING_APACHE_SSL_ADDITIONAL_SETTINGS,
            WebSetting.SETTING_NGINX_ADDITIONAL_SETTINGS
        ]
        for site in subscription.converted_dump.iter_domains():
            if site.is_virtual_hosting:
                for setting in site.web_settings:
                    if setting.name in web_server_directives_settings and not is_empty(setting.value):
                        return True

        return False

    def run(self, global_context, subscription):
        """Run action on given subscription
                
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        for site in subscription.converted_dump.iter_domains():
            if not site.is_virtual_hosting:
                continue

            site_web_settings = {
                setting.name: setting.value for setting in site.web_settings
            }

            global_context.hosting_repository.virtual_hosting_settings.set_web_server_additional_directives(
                subscription.name,
                site.name,
                WebServerDirectivesEntity(
                    apache_settings=site_web_settings.get(WebSetting.SETTING_APACHE_ADDITIONAL_SETTINGS),
                    apache_ssl_settings=site_web_settings.get(WebSetting.SETTING_APACHE_SSL_ADDITIONAL_SETTINGS),
                    nginx_settings=site_web_settings.get(WebSetting.SETTING_NGINX_ADDITIONAL_SETTINGS)
                )
            )
