import sys

from parallels.core import messages, MigrationError
from parallels.core.logging import get_logger
from parallels.core.panels import TargetPanels
from parallels.core.runners.base import BaseRunner
from parallels.core.runners.entities import ExecutionOptions
from parallels.core.utils.config_utils import ConfigSection, global_section

logger = get_logger(__name__)


class TargetPanelDetector(object):
    TARGET_PANEL_PLESK = 'plesk'
    TARGET_PANEL_PLESK_MULTI_SERVER = 'plesk_multi_server'

    @classmethod
    def detect(cls, global_context):
        """Detect target panel type

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode | None
        """
        target_panel_type = global_section(global_context.config).get('target-type')
        if target_panel_type is None:
            target_panel_type = cls._detect_target_panel(global_context)
            logger.debug(messages.DEBUG_TARGET_PANEL_AUTODETECT, target_panel_type)
        else:
            # accept both "plesk_multi_server" and "plesk-multi-server"
            target_panel_type = target_panel_type.replace('-', '_')
            logger.debug(messages.DEBUG_TARGET_PANEL_IN_CONFIG, target_panel_type)

        if target_panel_type is None:
            raise MigrationError(messages.MIGRATION_EXCEPTION_TARGET_PANEL_NAME_UNDEFINED)

        return target_panel_type

    @classmethod
    def _detect_target_panel(cls, global_context):
        """Try to automatically detect target panel type when it is not specified in explicit way.

        Usually target panel is Plesk, but sometimes it is Plesk Multi Server.

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode | None
        """
        plesk_section = ConfigSection(global_context.config, 'plesk')
        target_panel_type = TargetPanels.PLESK
        if plesk_section.getboolean('is-local', True) and not global_context.migrator_server.is_windows():
            with global_context.migrator_server.runner() as runner:
                assert isinstance(runner, BaseRunner)
                plesk_multi_server_module_name = 'plesk-multi-server'
                execution_results = runner.execute_command(
                    '''plesk db "SELECT name FROM Modules WHERE name = '{module_name}'"'''.format(
                        module_name=plesk_multi_server_module_name
                    ),
                    execution_options=ExecutionOptions(ignore_exit_code=True)
                )
                if sys.version_info.major >= 3:
                    module_name_bytes = plesk_multi_server_module_name.encode('utf-8')
                else:
                    module_name_bytes = plesk_multi_server_module_name
                if execution_results.exit_code == 0 and module_name_bytes in execution_results.stdout:
                    target_panel_type = TargetPanels.PLESK_MULTI_SERVER

        return target_panel_type
