import base64
from xml.etree import ElementTree

from parallels.core.hosting_repository.virtual_hosting_settings import VirtualHostingSettingsModel, \
    VirtualHostingSettingsEntity
from parallels.core.utils.common import is_empty
from parallels.core.utils.common.xml import xml_to_string_pretty, elem, text_elem
from parallels.plesk.hosting_repository.base import PleskBaseModel
from parallels.plesk.hosting_repository.utils.cli.backup_restore_helper import BackupRestoreHelperRestoreSubscriptionCli


class PleskVirtualHostingSettingsModel(VirtualHostingSettingsModel, PleskBaseModel):
    def get_virtual_hosting_settings(self, subscription_name, domain_name):
        """Get virtual hosting settings of subscription

        :type subscription_name: str | unicode
        :type domain_name: str | unicode
        :rtype: parallels.core.hosting_repository.virtual_hosting_settings.VirtualHostingSettingsEntity | None
        """
        query = """
          SELECT
            hosting.www_root AS www_root, 
            sys_users.login AS sysuser_login, 
            domains.displayName AS domain_display_name
          FROM domains
          JOIN hosting
            ON hosting.dom_id = domains.id
          JOIN sys_users
            ON sys_users.id = hosting.sys_user_id
          WHERE
            domains.name = %(domain_name)s
        """

        rows = self.plesk_server.query_panel_db(query, dict(domain_name=domain_name))

        if len(rows) == 0:
            return None

        row = rows[0]

        return VirtualHostingSettingsEntity(
            document_root=row["www_root"],
            sysuser_login=row["sysuser_login"],
            ip_addresses=self._get_ip_addresses(domain_name),
            hosting_ssl=self._get_hosting_ssl(domain_name),
            domain_display_name=row["domain_display_name"]
        )

    def set_web_server_additional_directives(self, subscription_name, domain_name, directives):
        """Set additional Apache/Nginx directives of domain

        :type subscription_name: str | unicode
        :type domain_name: str | unicode
        :type directives: parallels.core.hosting_repository.virtual_hosting_settings.WebServerDirectivesEntity
        :rtype: None 
        """
        settings = {}

        if not is_empty(directives.apache_settings):
            settings['additionalSettings'] = directives.apache_settings
        else:
            # PMM requires an empty option, and fails if option is absent in XML generated below
            settings['additionalSettings'] = ''
        if not is_empty(directives.apache_ssl_settings):
            settings['additionalSslSettings'] = directives.apache_ssl_settings
        else:
            # PMM requires an empty option, and fails if option is absent in XML generated below
            settings['additionalSslSettings'] = ''
        if not is_empty(directives.nginx_settings):
            settings['additionalNginxSettings'] = directives.nginx_settings
        else:
            # PMM requires an empty option, and fails if option is absent in XML generated below
            settings['additionalNginxSettings'] = ''

        xml = ElementTree.ElementTree(
            elem('subscription-info', [
                elem('web-settings', [
                    elem('setting', [
                        text_elem('name', setting_name),
                        text_elem('value', base64.b64encode(setting_value), {'encoding': 'base64'})
                    ])
                    for setting_name, setting_value in settings.items()
                ], {'vhost-name': domain_name.encode('idna')})
            ])
        )

        command = BackupRestoreHelperRestoreSubscriptionCli(
            # Extension restoration must be started via CLIGate.
            # When using direct CLI call files of extension get incorrect owner ('root' instead of 'psaadm').
            self.plesk_server.cligate_runner(),
            subscription_name.encode('idna'), xml_to_string_pretty(xml).decode('utf-8')
        )
        command.run()

    def _get_ip_addresses(self, domain_name):
        query = """
          SELECT 
            IP_Addresses.ip_address AS ip_address 
          FROM domains 
          JOIN DomainServices 
            ON (domains.id = DomainServices.dom_id AND DomainServices.type = 'web') 
          JOIN IpAddressesCollections 
            ON IpAddressesCollections.ipCollectionId = DomainServices.ipCollectionId 
          JOIN IP_Addresses ON IP_Addresses.id = IpAddressesCollections.ipAddressId 
          WHERE
            domains.name = %(domain_name)s
        """

        rows = self.plesk_server.query_panel_db(query, dict(domain_name=domain_name))

        ip_addresses = []

        for row in rows:
            if 'ip_address' in row:
                ip_addresses.append(row['ip_address'])

        return ip_addresses

    def _get_hosting_ssl(self, domain_name):
        query = """
          SELECT 
            hosting.ssl AS hosting_ssl 
          FROM domains 
          JOIN hosting 
            ON hosting.dom_id = domains.id 
          WHERE 
            domains.name = %(domain_name)s
        """
        rows = self.plesk_server.query_panel_db(query, dict(domain_name=domain_name))

        if len(rows) == 0:
            return None

        row = rows[0]

        return row["hosting_ssl"].lower() == u'true'
