import posixpath

from parallels.core.registry import Registry
from parallels.core.content.mail.rsync import CopyMailRsync
from parallels.core.content.mail.rsync import SourceMailDirectory
from parallels.core.utils.paths.mail_paths import MailboxDirectory


class PpcplCopyMailContentSourceDirectory(SourceMailDirectory):
    def __init__(self, subscription, domain, dump_agent):
        self.domain = domain
        self.subscription = subscription
        self.dump_agent = dump_agent
        self.temporary_directory = None

    def prepare(self):
        source_server = self.subscription.mail_source_server

        # run conversion on source server
        self.temporary_directory = source_server.get_session_file_path(posixpath.join('mail', self.domain.name))
        with source_server.runner() as runner_source:
            runner_source.mkdir(self.temporary_directory)

        maildir_pair = self._get_mailbox_maildir_mapping(
            self.subscription, self.domain, self.temporary_directory
        )
        return list(maildir_pair)

    def cleanup(self):
        source_server = self.subscription.mail_source_server
        if self.temporary_directory is not None:
            with source_server.runner() as runner:
                runner.remove_directory(self.temporary_directory)

    def _get_mailbox_maildir_mapping(self, subscription, domain, maildir_home):
        """Convert mailboxes to maildir; put them in a temporary directory.

        Return a pair of source, destination paths.
        """
        mailboxes = self._get_domain_mailboxes(domain)
        for mailbox in mailboxes:
            source_maildir = self._mailbox_to_maildir(subscription.mail_source_server, domain, mailbox, maildir_home)
            yield (source_maildir, MailboxDirectory(mailbox.name))

    def _mailbox_to_maildir(self, source_server, domain, mailbox, maildir_home):
        """Convert mailbox to maildir; return path to the generated Maildir.

        """
        converted_mail_dir = posixpath.join(maildir_home, mailbox.name)

        with source_server.runner() as runner_source:
            runner_source.mkdir(converted_mail_dir)

        self.dump_agent.convert_mail(
            Registry.get_instance().get_context().get_domain_filesystem_root(domain.name_idn),
            mailbox.name,
            converted_mail_dir
        )

        return converted_mail_dir

    @staticmethod
    def _get_domain_mailboxes(domain):
        """Return list of enabled mailboxes for given domain

        :type domain: parallels.core.dump.data_model.Subscription
        :rtype: list[parallels.core.dump.data_model.Mailbox]
        """
        return [mailbox for mailbox in domain.iter_mailboxes() if mailbox.enabled]


class PpcplCopyMailContent(CopyMailRsync):
    """Transfer mail content from PPCPL to Plesk server

    PPCPL mail content stored in mailbox format for indox folder and in native
    binary IMAP format for rest folders, so need to convert it into maildir
    format and then copy via rsync.
    """

    def __init__(self, dump_agent):
        class SourceDirectory(PpcplCopyMailContentSourceDirectory):
            def __init__(self, subscription, domain):
                super(SourceDirectory, self).__init__(subscription, domain, dump_agent)

        super(PpcplCopyMailContent, self).__init__(SourceDirectory)