from parallels.core import is_run_on_windows
from parallels.core.migrator_config import SourceConfig, FileTransportConfig
from parallels.core.registry import Registry
from parallels.core.utils.common import is_empty
from parallels.core.utils.config_utils import ConfigSelectionOption
from parallels.plesk.source.web.global_context import WebGlobalMigrationContext


class WebSourceConfig(SourceConfig, FileTransportConfig):
    def __init__(
        self,
        source_id, config_section, host, username, password, ftp_server_encoding, ssh_port,
        session_dir, base_url, document_root, files_root, target_domain, allow_insecure_connections,
        file_transport, transfer_files_mode, allow_auto_web_streaming, list_files_mode,
        ignore_passive_mode_server_ip, single_file_web_rpc_agent
    ):
        SourceConfig.__init__(
            self, source_id, config_section, None
        )
        FileTransportConfig.__init__(
            self, source_id, host, username, password, ftp_server_encoding, session_dir
        )
        self._ssh_port = ssh_port
        self._base_url = base_url
        self._document_root = document_root
        self._files_root = files_root
        self._target_domain = target_domain
        self._allow_insecure_connections = allow_insecure_connections
        self._file_transport = file_transport
        self._transfer_files_mode = transfer_files_mode
        self._allow_auto_web_streaming = allow_auto_web_streaming
        self._list_files_mode = list_files_mode
        self._ignore_passive_mode_server_ip = ignore_passive_mode_server_ip
        self._single_file_web_rpc_agent = single_file_web_rpc_agent

    @property
    def base_url_explicit(self):
        return self._base_url

    @property
    def base_url(self):
        context = Registry.get_instance().get_context()
        assert isinstance(context, WebGlobalMigrationContext)
        base_url = context.site_info_storage.get_base_url()
        if base_url is None:
            return self._base_url
        return base_url

    @property
    def document_root_explicit(self):
        return self._document_root

    @property
    def document_root(self):
        context = Registry.get_instance().get_context()
        assert isinstance(context, WebGlobalMigrationContext)
        document_root = context.site_info_storage.get_document_root()
        if document_root is None:
            return self._document_root
        return document_root

    @property
    def files_root(self):
        """
        :rtype: str | unicode | None
        """
        return self._files_root

    @property
    def target_domain(self):
        """Name of domain (addon domain, subdomain or subscription) to which the site should be transferred

        :rtype: str | unicode
        """
        return self._target_domain

    @property
    def effective_allow_insecure_connections(self):
        """Allow plain-text FTP, HTTP connections and HTTPS connections without valid SSL certificate
        Insecure connection can be allowed by allow_insecure_connections option or
        if any insecure protocol is set explicitly by user
        For example: base-url = "http://example.com"

        :rtype: bool
        """
        return (
                self._allow_insecure_connections
                or (not is_empty(self._base_url) and self._base_url.lstrip().lower().startswith('http://'))
        )

    @property
    def file_transport(self):
        """Way to work with files on source site
        See constants from parallels.plesk.source.web.config.FileTransportOption

        :rtype: str | unicode
        """
        return self._file_transport

    @property
    def transfer_files_mode(self):
        """Way to transfer folders and files from source site to target site
        See constants from parallels.plesk.source.web.config.TransferFilesModeOption

        :rtype: str | unicode
        """
        return self._transfer_files_mode

    @property
    def allow_auto_web_streaming(self):
        """Whether transfer of files with web streaming should be automatically selected when it makes sense.

        Web streaming makes sense in case when 'transfer-files-mode' is 'auto' and actual file transport is FTP.
        Web streaming is a beta feature, and so it is not selected by default.

        :rtype: bool
        """
        return self._allow_auto_web_streaming

    @property
    def list_files_mode(self):
        """Way to list files (build files tree) on source site
        See constants from parallels.plesk.source.web.config.ListFilesModeOption

        :rtype: str | unicode
        """
        return self._list_files_mode

    @property
    def ignore_passive_mode_server_ip(self):
        """Whether to ignore IP address returned by FTP server when opening data channel in passive mode

        When is set to true, IP address returned by FTP server when opening data channel
        in passive mode is ignored. That option could be necessary because some misconfigured
        FTP servers return internal IPs, which could not be used to connect to the server.
        When the option is set, hostname specified for control connection to the FTP server
        will be used for data connections.

        :rtype: bool | None
        """
        return self._ignore_passive_mode_server_ip

    @property
    def single_file_web_rpc_agent(self):
        """Deploy Web RPC agent as single PHP file
        This method provides better performance if file transport is slow

        :rtype: bool | None
        """
        return self._single_file_web_rpc_agent

    @property
    def ssh_port(self):
        """Port to connect to domain by SSH

        :rtype: int
        """
        return self._ssh_port


class ListFilesModeOption(ConfigSelectionOption):
    AUTO = 'auto'
    FILE_TRANSPORT = 'file-transport'
    WEB_RPC_AGENT = 'web-rpc-agent'
    HYBRID = 'hybrid'

    @property
    def name(self):
        """Return name of the option

        :rtype: str
        """
        return 'list-files-mode'

    @property
    def allowed_values(self):
        """Return list of allowed values for this option

        :rtype: list[str]
        """
        return [
            self.AUTO,
            self.FILE_TRANSPORT,
            self.WEB_RPC_AGENT,
            self.HYBRID
        ]

    @property
    def default(self):
        """Return default value for this option, if it was not specified in configuration file

        :rtype: str
        """
        return self.AUTO


class FileTransportOption(ConfigSelectionOption):
    AUTO = 'auto'
    SSH = 'ssh'
    FTP = 'ftp'

    @property
    def name(self):
        """Return name of the option

        :rtype: str
        """
        return 'file-transport'

    @property
    def allowed_values(self):
        """Return list of allowed values for this option

        :rtype: list[str]
        """
        return [
            self.AUTO,
            self.SSH,
            self.FTP,
        ]

    @property
    def default(self):
        """Return default value for this option, if it was not specified in configuration file

        :rtype: str
        """
        return self.AUTO


class TransferFilesModeOption(ConfigSelectionOption):
    AUTO = 'auto'
    FILE_TRANSPORT = 'file-transport'
    FTP = 'ftp'
    SSH_RSYNC = 'ssh-rsync'
    SSH_SCP = 'ssh-scp'
    WEB_STREAMING = 'web-streaming'

    @property
    def name(self):
        """Return name of the option

        :rtype: str
        """
        return 'transfer-files-mode'

    @property
    def allowed_values(self):
        """Return list of allowed values for this option

        :rtype: list[str]
        """
        if is_run_on_windows():
            return [
                self.AUTO,
                self.FTP,
                self.WEB_STREAMING,
            ]
        else:
            return [
                self.AUTO,
                self.FILE_TRANSPORT,
                self.FTP,
                self.SSH_RSYNC,
                self.SSH_SCP,
                self.WEB_STREAMING,
            ]

    @property
    def default(self):
        """Return default value for this option, if it was not specified in configuration file

        :rtype: str
        """
        return self.AUTO
